diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90915da960d81ca7c7819f097503369cdb9e071e..cf90a25ccea694ee3bd223587ec29f3d63667edb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,12 @@ find_package(ROOT COMPONENTS Core RIO Tree MathCore GenVector Geom REQUIRED)
 find_package(DD4hep COMPONENTS DDG4 DDG4IO DDRec REQUIRED)
 
 find_package(Acts REQUIRED COMPONENTS Core PluginIdentification PluginTGeo PluginDD4hep PluginJson)
+set(Acts_VERSION_MIN "15.1.0")
+set(Acts_VERSION "${Acts_VERSION_MAJOR}.${Acts_VERSION_MINOR}.${Acts_VERSION_PATCH}")
+if(${Acts_VERSION} VERSION_LESS ${Acts_VERSION_MIN}
+   AND NOT "${Acts_VERSION}" STREQUAL "9.9.9")
+  message(FATAL_ERROR "Acts version ${Acts_VERSION_MIN} or higher required, but ${Acts_VERSION} found")
+endif()
 add_definitions("-DActs_VERSION_MAJOR=${Acts_VERSION_MAJOR}")
 add_definitions("-DActs_VERSION_MINOR=${Acts_VERSION_MINOR}")
 add_definitions("-DActs_VERSION_PATCH=${Acts_VERSION_PATCH}")
diff --git a/JugTrack/JugTrack/GeometryContainers.hpp b/JugTrack/JugTrack/GeometryContainers.hpp
index 3e580cd2f28a2a439634e8084e2f3e003912863f..99cc27ac33a492e401dd9e5b988cc34f4ab13eda 100644
--- a/JugTrack/JugTrack/GeometryContainers.hpp
+++ b/JugTrack/JugTrack/GeometryContainers.hpp
@@ -43,6 +43,12 @@ struct GeometryIdGetter {
       -> decltype(thing.geometryId(), Acts::GeometryIdentifier()) {
     return thing.geometryId();
   }
+  // support reference_wrappers around such types as well
+  template <typename T>
+  inline auto operator()(std::reference_wrapper<T> thing) const
+      -> decltype(thing.get().geometryId(), Acts::GeometryIdentifier()) {
+    return thing.get().geometryId();
+  }
 };
 
 struct CompareGeometryId {
diff --git a/JugTrack/JugTrack/IndexSourceLink.hpp b/JugTrack/JugTrack/IndexSourceLink.hpp
index 5124ac3761632130a6999f696127df7dbeaae056..d64981a48995fa306ebffcb31ef1001d63401714 100644
--- a/JugTrack/JugTrack/IndexSourceLink.hpp
+++ b/JugTrack/JugTrack/IndexSourceLink.hpp
@@ -11,6 +11,8 @@
 #include "JugTrack/GeometryContainers.hpp"
 #include "JugTrack/Index.hpp"
 
+#include "Acts/EventData/SourceLink.hpp"
+
 #include <cassert>
 
 namespace Jug {
@@ -24,31 +26,28 @@ namespace Jug {
   /// Using an index instead of e.g. a pointer, means source link and
   /// measurement are decoupled and the measurement represenation can be
   /// easily changed without having to also change the source link.
-  class IndexSourceLink final {
+  class IndexSourceLink final : public Acts::SourceLink {
   public:
     /// Construct from geometry identifier and index.
-    constexpr IndexSourceLink(Acts::GeometryIdentifier gid, Index idx) : m_geometryId(gid), m_index(idx) {}
+    constexpr IndexSourceLink(Acts::GeometryIdentifier gid, Index idx) : SourceLink(gid), m_index(idx) {}
 
     // Construct an invalid source link. Must be default constructible to
     /// satisfy SourceLinkConcept.
-    IndexSourceLink()                       = default;
+    IndexSourceLink() : SourceLink{Acts::GeometryIdentifier{}} {}
     IndexSourceLink(const IndexSourceLink&) = default;
     IndexSourceLink(IndexSourceLink&&)      = default;
     IndexSourceLink& operator=(const IndexSourceLink&) = default;
     IndexSourceLink& operator=(IndexSourceLink&&) = default;
 
-    /// Access the geometry identifier.
-    constexpr Acts::GeometryIdentifier geometryId() const { return m_geometryId; }
     /// Access the index.
     constexpr Index index() const { return m_index; }
 
   public:
-    Acts::GeometryIdentifier m_geometryId;
     Index                    m_index;
 
     friend constexpr bool operator==(const IndexSourceLink& lhs, const IndexSourceLink& rhs)
     {
-      return (lhs.m_geometryId == rhs.m_geometryId) and (lhs.m_index == rhs.m_index);
+      return (lhs.geometryId() == rhs.geometryId()) and (lhs.m_index == rhs.m_index);
     }
     friend constexpr bool operator!=(const IndexSourceLink& lhs, const IndexSourceLink& rhs) { return not(lhs == rhs); }
   };
@@ -57,12 +56,14 @@ namespace Jug {
   ///
   /// Since the source links provide a `.geometryId()` accessor, they can be
   /// stored in an ordered geometry container.
-  using IndexSourceLinkContainer = GeometryIdMultiset<IndexSourceLink>;
+  using IndexSourceLinkContainer =
+    GeometryIdMultiset<std::reference_wrapper<const IndexSourceLink>>;
 
   /// Accessor for the above source link container
   ///
   /// It wraps up a few lookup methods to be used in the Combinatorial Kalman
   /// Filter
-  using IndexSourceLinkAccessor = GeometryIdMultisetAccessor<IndexSourceLink>;
+  using IndexSourceLinkAccessor =
+    GeometryIdMultisetAccessor<std::reference_wrapper<const IndexSourceLink>>;
 
 } // namespace Jug
diff --git a/JugTrack/JugTrack/Measurement.hpp b/JugTrack/JugTrack/Measurement.hpp
index aa4c1f9bf2bd3c4e21078edf244daf474a60f5d3..7af36fa344831c07d1b32c64778642eafc90807d 100644
--- a/JugTrack/JugTrack/Measurement.hpp
+++ b/JugTrack/JugTrack/Measurement.hpp
@@ -2,6 +2,8 @@
 #define JugTrack_Measurement_HH
 
 #include "Acts/EventData/Measurement.hpp"
+#include "Acts/EventData/MultiTrajectory.hpp"
+#include "Acts/EventData/SourceLink.hpp"
 #include "JugTrack/IndexSourceLink.hpp"
 
 #include <cassert>
@@ -10,7 +12,7 @@
 namespace Jug {
 
   /// Variable measurement type that can contain all possible combinations.
-  using Measurement = ::Acts::BoundVariantMeasurement<IndexSourceLink>;
+  using Measurement = ::Acts::BoundVariantMeasurement;
   /// Container of measurements.
   ///
   /// In contrast to the source links, the measurements themself must not be
@@ -29,14 +31,15 @@ namespace Jug {
     /// Find the measurement corresponding to the source link.
     ///
     /// @tparam parameters_t Track parameters type
-    /// @param sourceLink Input source link
-    /// @param parameters Input track parameters (unused)
-    template <typename parameters_t>
-    const Measurement& operator()(const IndexSourceLink& sourceLink, const parameters_t& /* parameters */) const
-    {
-      assert(m_measurements and "Undefined measurement container in DigitizedCalibrator");
-      assert((sourceLink.index() < m_measurements->size()) and "Source link index is outside the container bounds");
-      return (*m_measurements)[sourceLink.m_index];
+    /// @param gctx The geometry context (unused)
+    /// @param trackState The track state to calibrate
+    void calibrate(const Acts::GeometryContext& /*gctx*/,
+                   Acts::MultiTrajectory::TrackStateProxy trackState) const {
+      const auto& sourceLink =
+          static_cast<const IndexSourceLink&>(trackState.uncalibrated());
+      std::visit(
+          [&trackState](const auto& meas) { trackState.setCalibrated(meas); },
+          (*m_measurements)[sourceLink.index()]);
     }
 
   private:
diff --git a/JugTrack/JugTrack/Trajectories.hpp b/JugTrack/JugTrack/Trajectories.hpp
index 30d1983dfed683f9c559ed04bded319c79862d9b..a104661b92b0d77d5acb0692269abac345ca4129 100644
--- a/JugTrack/JugTrack/Trajectories.hpp
+++ b/JugTrack/JugTrack/Trajectories.hpp
@@ -21,7 +21,7 @@ namespace Jug {
 struct Trajectories final {
  public:
   /// (Reconstructed) trajectory with multiple states.
-  using MultiTrajectory = ::Acts::MultiTrajectory<IndexSourceLink>;
+  using MultiTrajectory = ::Acts::MultiTrajectory;
   /// Fitted parameters identified by indices in the multi trajectory.
   using IndexedParameters = std::unordered_map<size_t, TrackParameters>;
 
diff --git a/JugTrack/src/components/CKFTracking.cpp b/JugTrack/src/components/CKFTracking.cpp
index 035dfcbe45e5cef52fe6628e43485ad72716e730..172cb16d4090fe891acdb1a69d6aaad05b6b3737 100644
--- a/JugTrack/src/components/CKFTracking.cpp
+++ b/JugTrack/src/components/CKFTracking.cpp
@@ -88,9 +88,13 @@ namespace Jug::Reco {
       debug() << "B(z=" << z << " mm) = " << b.transpose()  << " T"   << endmsg;
     }
 
-    // chi2 and #sourclinks per surface cutoffs
+    // eta bins, chi2 and #sourclinks per surface cutoffs
     m_sourcelinkSelectorCfg = {
-        {Acts::GeometryIdentifier(), {m_chi2CutOff, m_numMeasurementsCutOff}},
+        {Acts::GeometryIdentifier(),
+            {m_etaBins, m_chi2CutOff,
+                {m_numMeasurementsCutOff.begin(), m_numMeasurementsCutOff.end()}
+            }
+        },
     };
     m_trackFinderFunc = CKFTracking::makeCKFTrackingFunction(m_geoSvc->trackingGeometry(), m_BField);
     auto im = _msgMap.find(msgLevel());
@@ -120,12 +124,27 @@ namespace Jug::Reco {
     Acts::PropagatorPlainOptions pOptions;
     pOptions.maxSteps = 10000;
 
+    MeasurementCalibrator calibrator{*measurements};
+    Acts::GainMatrixUpdater kfUpdater;
+    Acts::GainMatrixSmoother kfSmoother;
+    Acts::MeasurementSelector measSel{m_sourcelinkSelectorCfg};
+
+    Acts::CombinatorialKalmanFilterExtensions extensions;
+    extensions.calibrator.connect<&MeasurementCalibrator::calibrate>(&calibrator);
+    extensions.updater.connect<&Acts::GainMatrixUpdater::operator()>(&kfUpdater);
+    extensions.smoother.connect<&Acts::GainMatrixSmoother::operator()>(
+        &kfSmoother);
+    extensions.measurementSelector.connect<&Acts::MeasurementSelector::select>(
+        &measSel);
+
     // Set the CombinatorialKalmanFilter options
     CKFTracking::TrackFinderOptions options(
-        m_geoctx, m_fieldctx, m_calibctx, IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements),
-        Acts::MeasurementSelector(m_sourcelinkSelectorCfg), Acts::LoggerWrapper{logger()}, pOptions, &(*pSurface));
+        m_geoctx, m_fieldctx, m_calibctx,
+        IndexSourceLinkAccessor(), extensions,
+        Acts::LoggerWrapper{logger()},
+        pOptions, &(*pSurface));
 
-    auto results = m_trackFinderFunc(*src_links, *init_trk_params, options);
+    auto results = (*m_trackFinderFunc)(*src_links, *init_trk_params, options);
 
     for (std::size_t iseed = 0; iseed < init_trk_params->size(); ++iseed) {
 
diff --git a/JugTrack/src/components/CKFTracking.h b/JugTrack/src/components/CKFTracking.h
index 384f71e2b19baede70154e369e75c45a685bcb4c..375ef4a17ff8c1ef3a7e6547a268ceea8770a9e1 100644
--- a/JugTrack/src/components/CKFTracking.h
+++ b/JugTrack/src/components/CKFTracking.h
@@ -37,16 +37,26 @@ class CKFTracking : public GaudiAlgorithm {
 public:
   /// Track finder function that takes input measurements, initial trackstate
   /// and track finder options and returns some track-finder-specific result.
-  using TrackFinderOptions  = Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor, MeasurementCalibrator, Acts::MeasurementSelector>;
-  using TrackFinderResult   = std::vector<Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>>;
-  using CKFTrackingFunction = std::function<TrackFinderResult(
-      const IndexSourceLinkContainer&, const TrackParametersContainer&, const TrackFinderOptions&)>;
+  using TrackFinderOptions  = Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor>;
+  using TrackFinderResult   = std::vector<Acts::Result<Acts::CombinatorialKalmanFilterResult>>;
+
+  /// Find function that takes the above parameters
+  /// @note This is separated into a virtual interface to keep compilation units
+  /// small
+  class CKFTrackingFunction {
+   public:
+    virtual ~CKFTrackingFunction() = default;
+    virtual TrackFinderResult operator()(const IndexSourceLinkContainer&,
+                                         const TrackParametersContainer&,
+                                         const TrackFinderOptions&) const = 0;
+  };
 
   /// Create the track finder function implementation.
   /// The magnetic field is intentionally given by-value since the variant
   /// contains shared_ptr anyways.
-  static CKFTrackingFunction makeCKFTrackingFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
-                                                     std::shared_ptr<const Acts::MagneticFieldProvider> magneticField);
+  static std::shared_ptr<CKFTrackingFunction> makeCKFTrackingFunction(
+    std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
+    std::shared_ptr<const Acts::MagneticFieldProvider> magneticField);
 
 public:
   DataHandle<IndexSourceLinkContainer> m_inputSourceLinks{"inputSourceLinks", Gaudi::DataHandle::Reader, this};
@@ -55,10 +65,11 @@ public:
                                                                      Gaudi::DataHandle::Reader, this};
   DataHandle<TrajectoriesContainer> m_outputTrajectories{"outputTrajectories", Gaudi::DataHandle::Writer, this};
 
-  Gaudi::Property<double> m_chi2CutOff{this, "chi2CutOff", 15.};
-  Gaudi::Property<size_t> m_numMeasurementsCutOff{this, "numMeasurementsCutOff", 10};
+  Gaudi::Property<std::vector<double>> m_etaBins{this, "etaBins", {}};
+  Gaudi::Property<std::vector<double>> m_chi2CutOff{this, "chi2CutOff", {15.}};
+  Gaudi::Property<std::vector<size_t>> m_numMeasurementsCutOff{this, "numMeasurementsCutOff", {10}};
 
-  CKFTrackingFunction m_trackFinderFunc;
+  std::shared_ptr<CKFTrackingFunction> m_trackFinderFunc;
   SmartIF<IGeoSvc> m_geoSvc;
 
   std::shared_ptr<const Jug::BField::DD4hepBField> m_BField = nullptr;
diff --git a/JugTrack/src/components/CKFTrackingFunction.cpp b/JugTrack/src/components/CKFTrackingFunction.cpp
index b4993eb5e0a51825c3b457bc7cdbea1df1bb3b80..be6893eb3ce0117f16cb8ee9bb606521fba2ef60 100644
--- a/JugTrack/src/components/CKFTrackingFunction.cpp
+++ b/JugTrack/src/components/CKFTrackingFunction.cpp
@@ -28,13 +28,14 @@ namespace {
   using Stepper    = Acts::EigenStepper<>;
   using Navigator  = Acts::Navigator;
   using Propagator = Acts::Propagator<Stepper, Navigator>;
-  using CKF        = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>;
+  using CKF        = Acts::CombinatorialKalmanFilter<Propagator>;
 
   /** Finder implmentation .
    *
    * \ingroup track
    */
-  struct CKFTrackingFunctionImpl {
+  struct CKFTrackingFunctionImpl
+    : public Jug::Reco::CKFTracking::CKFTrackingFunction {
     CKF trackFinder;
 
     CKFTrackingFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {}
@@ -42,7 +43,8 @@ namespace {
     Jug::Reco::CKFTracking::TrackFinderResult
     operator()(const Jug::IndexSourceLinkContainer&                        sourcelinks,
                const Jug::TrackParametersContainer&                        initialParameters,
-               const Jug::Reco::CKFTracking::TrackFinderOptions& options) const
+               const Jug::Reco::CKFTracking::TrackFinderOptions& options)
+               const override
     {
       return trackFinder.findTracks(sourcelinks, initialParameters, options);
     };
@@ -52,7 +54,8 @@ namespace {
 
 namespace Jug::Reco {
 
-  CKFTracking::CKFTrackingFunction CKFTracking::makeCKFTrackingFunction(
+  std::shared_ptr<CKFTracking::CKFTrackingFunction>
+  CKFTracking::makeCKFTrackingFunction(
       std::shared_ptr<const Acts::TrackingGeometry>      trackingGeometry,
       std::shared_ptr<const Acts::MagneticFieldProvider> magneticField)
   {
@@ -67,7 +70,7 @@ namespace Jug::Reco {
     CKF        trackFinder(std::move(propagator));
 
     // build the track finder functions. onws the track finder object.
-    return CKFTrackingFunctionImpl(std::move(trackFinder));
+    return std::make_shared<CKFTrackingFunctionImpl>(std::move(trackFinder));
   }
 
 } // namespace Jug::Reco
diff --git a/JugTrack/src/components/SingleTrackSourceLinker.cpp b/JugTrack/src/components/SingleTrackSourceLinker.cpp
index b05406a61450676164acc56ea5a424a6d3452ee2..06c92777baa3b55fb0e51668367c97ec8ecf0523 100644
--- a/JugTrack/src/components/SingleTrackSourceLinker.cpp
+++ b/JugTrack/src/components/SingleTrackSourceLinker.cpp
@@ -1,5 +1,3 @@
-#include "JugTrack/GeometryContainers.hpp"
-
 // Gaudi
 #include "Gaudi/Property.h"
 #include "GaudiAlg/GaudiAlgorithm.h"
@@ -27,6 +25,7 @@
 #include "JugTrack/IndexSourceLink.hpp"
 #include "JugTrack/Measurement.hpp"
 #include "JugTrack/ProtoTrack.hpp"
+#include "JugTrack/GeometryContainers.hpp"
 
 #include "eicd/TrackerHitCollection.h"
 
@@ -40,10 +39,11 @@ namespace Jug::Reco {
    */
   class SingleTrackSourceLinker : public GaudiAlgorithm {
   public:
-    DataHandle<eic::TrackerHitCollection> m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader, this};
-    DataHandle<IndexSourceLinkContainer>  m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this};
-    DataHandle<MeasurementContainer>      m_outputMeasurements{"outputMeasurements", Gaudi::DataHandle::Writer, this};
-    DataHandle<ProtoTrackContainer>       m_outputProtoTracks{"outputProtoTracks", Gaudi::DataHandle::Writer, this};
+    DataHandle<eic::TrackerHitCollection>  m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader, this};
+    DataHandle<std::list<IndexSourceLink>> m_sourceLinkStorage{"sourceLinkStorage", Gaudi::DataHandle::Writer, this};
+    DataHandle<IndexSourceLinkContainer>   m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this};
+    DataHandle<MeasurementContainer>       m_outputMeasurements{"outputMeasurements", Gaudi::DataHandle::Writer, this};
+    DataHandle<ProtoTrackContainer>        m_outputProtoTracks{"outputProtoTracks", Gaudi::DataHandle::Writer, this};
     /// Pointer to the geometry service
     SmartIF<IGeoSvc> m_geoSvc;
 
@@ -51,6 +51,7 @@ namespace Jug::Reco {
     SingleTrackSourceLinker(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc)
     {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
+      declareProperty("sourceLinkStorage", m_sourceLinkStorage, "");
       declareProperty("outputSourceLinks", m_outputSourceLinks, "");
       declareProperty("outputMeasurements", m_outputMeasurements, "");
       declareProperty("outputProtoTracks", m_outputProtoTracks, "");
@@ -74,6 +75,7 @@ namespace Jug::Reco {
       // input collection
       const eic::TrackerHitCollection* hits = m_inputHitCollection.get();
       // Create output collections
+      auto linkStorage  = m_sourceLinkStorage.createAndPut();
       auto sourceLinks  = m_outputSourceLinks.createAndPut();
       auto measurements = m_outputMeasurements.createAndPut();
       auto protoTracks  = m_outputProtoTracks.createAndPut();
@@ -146,7 +148,8 @@ namespace Jug::Reco {
         // cov << 0.05, 0., 0., 0., 0.05, 0., 0., 0., 900. * Acts::UnitConstants::ps * Acts::UnitConstants::ps;
         // Acts::Vector3 par(localX, localY, simHit.time());
 
-        IndexSourceLink sourceLink(surface->geometryId(), ihit);
+        linkStorage->emplace_back(surface->geometryId(), ihit);
+        IndexSourceLink& sourceLink = linkStorage->back();
         auto            meas =
             Acts::makeMeasurement(sourceLink, pos, cov, Acts::eBoundLoc0, Acts::eBoundLoc1); //, Acts::eBoundTime);
 
@@ -174,7 +177,7 @@ namespace Jug::Reco {
 
         // add to output containers. since the input is already geometry-order,
         // new elements in geometry containers can just be appended at the end.
-        sourceLinks->emplace_hint(sourceLinks->end(), std::move(sourceLink));
+        sourceLinks->emplace_hint(sourceLinks->end(), sourceLink);
         measurements->emplace_back(std::move(meas));
 
         ihit++;
diff --git a/JugTrack/src/components/TrackFindingAlgorithm.cpp b/JugTrack/src/components/TrackFindingAlgorithm.cpp
index 8e83158a41c24e467f1510642e51c4f482275646..73b65c022661c99098d1280941b719c5824b1e2f 100644
--- a/JugTrack/src/components/TrackFindingAlgorithm.cpp
+++ b/JugTrack/src/components/TrackFindingAlgorithm.cpp
@@ -89,9 +89,13 @@ namespace Jug::Reco {
       debug() << "B(z=" << z << " mm) = " << b.transpose()  << " T"   << endmsg;
     }
 
-    // chi2 and #sourclinks per surface cutoffs
+    // eta bins, chi2 and #sourclinks per surface cutoffs
     m_sourcelinkSelectorCfg = {
-        {Acts::GeometryIdentifier(), {m_chi2CutOff, m_numMeasurementsCutOff}},
+        {Acts::GeometryIdentifier(),
+            {m_etaBins, m_chi2CutOff,
+                {m_numMeasurementsCutOff.begin(), m_numMeasurementsCutOff.end()}
+            }
+        },
     };
     m_trackFinderFunc = TrackFindingAlgorithm::makeTrackFinderFunction(m_geoSvc->trackingGeometry(), m_BField);
     auto im = _msgMap.find(msgLevel());
@@ -121,12 +125,27 @@ namespace Jug::Reco {
     Acts::PropagatorPlainOptions pOptions;
     pOptions.maxSteps = 10000;
 
+    MeasurementCalibrator calibrator{*measurements};
+    Acts::GainMatrixUpdater kfUpdater;
+    Acts::GainMatrixSmoother kfSmoother;
+    Acts::MeasurementSelector measSel{m_sourcelinkSelectorCfg};
+
+    Acts::CombinatorialKalmanFilterExtensions extensions;
+    extensions.calibrator.connect<&MeasurementCalibrator::calibrate>(&calibrator);
+    extensions.updater.connect<&Acts::GainMatrixUpdater::operator()>(&kfUpdater);
+    extensions.smoother.connect<&Acts::GainMatrixSmoother::operator()>(
+        &kfSmoother);
+    extensions.measurementSelector.connect<&Acts::MeasurementSelector::select>(
+        &measSel);
+
     // Set the CombinatorialKalmanFilter options
     TrackFindingAlgorithm::TrackFinderOptions options(
-        m_geoctx, m_fieldctx, m_calibctx, IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements),
-        Acts::MeasurementSelector(m_sourcelinkSelectorCfg), Acts::LoggerWrapper{logger()}, pOptions, &(*pSurface));
+        m_geoctx, m_fieldctx, m_calibctx,
+        IndexSourceLinkAccessor(), extensions,
+        Acts::LoggerWrapper{logger()},
+        pOptions, &(*pSurface));
 
-    auto results = m_trackFinderFunc(*src_links, *init_trk_params, options);
+    auto results = (*m_trackFinderFunc)(*src_links, *init_trk_params, options);
 
     for (std::size_t iseed = 0; iseed < init_trk_params->size(); ++iseed) {
 
diff --git a/JugTrack/src/components/TrackFindingAlgorithm.h b/JugTrack/src/components/TrackFindingAlgorithm.h
index 93deba43a8e04147b770702c9b155bd17f559380..ac6ed014eab5170b34d5830ee8f5d193d93635a7 100644
--- a/JugTrack/src/components/TrackFindingAlgorithm.h
+++ b/JugTrack/src/components/TrackFindingAlgorithm.h
@@ -37,16 +37,26 @@ class TrackFindingAlgorithm : public GaudiAlgorithm {
 public:
   /// Track finder function that takes input measurements, initial trackstate
   /// and track finder options and returns some track-finder-specific result.
-  using TrackFinderOptions  = Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor, MeasurementCalibrator, Acts::MeasurementSelector>;
-  using TrackFinderResult   = std::vector<Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>>;
-  using TrackFinderFunction = std::function<TrackFinderResult(
-      const IndexSourceLinkContainer&, const TrackParametersContainer&, const TrackFinderOptions&)>;
+  using TrackFinderOptions  = Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor>;
+  using TrackFinderResult   = std::vector<Acts::Result<Acts::CombinatorialKalmanFilterResult>>;
+
+  /// Find function that takes the above parameters
+  /// @note This is separated into a virtual interface to keep compilation units
+  /// small
+  class TrackFinderFunction {
+   public:
+    virtual ~TrackFinderFunction() = default;
+    virtual TrackFinderResult operator()(const IndexSourceLinkContainer&,
+                                         const TrackParametersContainer&,
+                                         const TrackFinderOptions&) const = 0;
+  };
 
   /// Create the track finder function implementation.
   /// The magnetic field is intentionally given by-value since the variant
   /// contains shared_ptr anyways.
-  static TrackFinderFunction makeTrackFinderFunction(std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
-                                                     std::shared_ptr<const Acts::MagneticFieldProvider> magneticField);
+  static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction(
+    std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
+    std::shared_ptr<const Acts::MagneticFieldProvider> magneticField);
 
 public:
   DataHandle<IndexSourceLinkContainer> m_inputSourceLinks{"inputSourceLinks", Gaudi::DataHandle::Reader, this};
@@ -55,10 +65,11 @@ public:
                                                                      Gaudi::DataHandle::Reader, this};
   DataHandle<TrajectoriesContainer> m_outputTrajectories{"outputTrajectories", Gaudi::DataHandle::Writer, this};
 
-  Gaudi::Property<double> m_chi2CutOff{this, "chi2CutOff", 15.};
-  Gaudi::Property<size_t> m_numMeasurementsCutOff{this, "numMeasurementsCutOff", 10};
+  Gaudi::Property<std::vector<double>> m_etaBins{this, "etaBins", {}};
+  Gaudi::Property<std::vector<double>> m_chi2CutOff{this, "chi2CutOff", {15.}};
+  Gaudi::Property<std::vector<size_t>> m_numMeasurementsCutOff{this, "numMeasurementsCutOff", {10}};
 
-  TrackFinderFunction m_trackFinderFunc;
+  std::shared_ptr<TrackFinderFunction> m_trackFinderFunc;
   SmartIF<IGeoSvc> m_geoSvc;
 
   std::shared_ptr<const Jug::BField::DD4hepBField> m_BField = nullptr;
diff --git a/JugTrack/src/components/TrackFindingAlgorithmFunction.cpp b/JugTrack/src/components/TrackFindingAlgorithmFunction.cpp
index 1e2bfecee2d6b316c0dbf4fb602e0a7b243dc848..921b3e26399434a8b7efba9f69c981c4150a92be 100644
--- a/JugTrack/src/components/TrackFindingAlgorithmFunction.cpp
+++ b/JugTrack/src/components/TrackFindingAlgorithmFunction.cpp
@@ -28,13 +28,14 @@ namespace {
   using Stepper    = Acts::EigenStepper<>;
   using Navigator  = Acts::Navigator;
   using Propagator = Acts::Propagator<Stepper, Navigator>;
-  using CKF        = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>;
+  using CKF        = Acts::CombinatorialKalmanFilter<Propagator>;
 
   /** Finder implmentation .
    *
    * \ingroup track
    */
-  struct TrackFinderFunctionImpl {
+  struct TrackFinderFunctionImpl
+    : public Jug::Reco::TrackFindingAlgorithm::TrackFinderFunction {
     CKF trackFinder;
 
     TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {}
@@ -42,7 +43,8 @@ namespace {
     Jug::Reco::TrackFindingAlgorithm::TrackFinderResult
     operator()(const Jug::IndexSourceLinkContainer&                        sourcelinks,
                const Jug::TrackParametersContainer&                        initialParameters,
-               const Jug::Reco::TrackFindingAlgorithm::TrackFinderOptions& options) const
+               const Jug::Reco::TrackFindingAlgorithm::TrackFinderOptions& options)
+               const override
     {
       return trackFinder.findTracks(sourcelinks, initialParameters, options);
     };
@@ -52,7 +54,8 @@ namespace {
 
 namespace Jug::Reco {
 
-  TrackFindingAlgorithm::TrackFinderFunction TrackFindingAlgorithm::makeTrackFinderFunction(
+  std::shared_ptr<TrackFindingAlgorithm::TrackFinderFunction>
+  TrackFindingAlgorithm::makeTrackFinderFunction(
       std::shared_ptr<const Acts::TrackingGeometry>      trackingGeometry,
       std::shared_ptr<const Acts::MagneticFieldProvider> magneticField)
   {
@@ -67,7 +70,7 @@ namespace Jug::Reco {
     CKF        trackFinder(std::move(propagator));
 
     // build the track finder functions. onws the track finder object.
-    return TrackFinderFunctionImpl(std::move(trackFinder));
+    return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder));
   }
 
 } // namespace Jug::Reco
diff --git a/JugTrack/src/components/TrackFittingAlgorithm.cpp b/JugTrack/src/components/TrackFittingAlgorithm.cpp
index 31b3200c8368ecd1378d0c5cb748191e1325f0c1..640ff7c60fc03342e10c57720ac8aa9379a2de89 100644
--- a/JugTrack/src/components/TrackFittingAlgorithm.cpp
+++ b/JugTrack/src/components/TrackFittingAlgorithm.cpp
@@ -104,16 +104,19 @@ namespace Jug::Reco {
     // kfOptions.multipleScattering = m_cfg.multipleScattering;
     // kfOptions.energyLoss         = m_cfg.energyLoss;
 
-    #if Acts_VERSION_MAJOR < 14
-    Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder> kfOptions(
-        m_geoctx, m_fieldctx, m_calibctx, MeasurementCalibrator(*measurements),
-        Acts::VoidOutlierFinder(), Acts::LoggerWrapper{logger()}, pOptions, &(*pSurface));
-    #else
-    Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic> kfOptions(
-        m_geoctx, m_fieldctx, m_calibctx, MeasurementCalibrator(*measurements),
-        Acts::VoidOutlierFinder(), Acts::VoidReverseFilteringLogic(),
-        Acts::LoggerWrapper{logger()}, pOptions, &(*pSurface));
-    #endif
+    Acts::KalmanFitterExtensions extensions;
+    MeasurementCalibrator calibrator{*measurements};
+    extensions.calibrator.connect<&MeasurementCalibrator::calibrate>(&calibrator);
+    Acts::GainMatrixUpdater kfUpdater;
+    Acts::GainMatrixSmoother kfSmoother;
+    extensions.updater.connect<&Acts::GainMatrixUpdater::operator()>(&kfUpdater);
+    extensions.smoother.connect<&Acts::GainMatrixSmoother::operator()>(
+        &kfSmoother);
+
+    Acts::KalmanFitterOptions kfOptions(
+        m_geoctx, m_fieldctx, m_calibctx, extensions,
+        Acts::LoggerWrapper{logger()}, Acts::PropagatorPlainOptions(),
+        &(*pSurface));
 
     // used for processing the data
     std::vector<IndexSourceLink>      trackSourceLinks;
@@ -142,18 +145,16 @@ namespace Jug::Reco {
       trackSourceLinks.reserve(protoTrack.size());
 
       for (auto hitIndex : protoTrack) {
-        if (msgLevel(MSG::DEBUG)) {
-          debug() << " hit  index = " << hitIndex << endmsg;
-        }
-        auto sourceLink = sourceLinks->nth(hitIndex);
-        auto geoId      = sourceLink->geometryId();
-        if (sourceLink == sourceLinks->end()) {
-          ACTS_FATAL("Proto track " << itrack << " contains invalid hit index "
+        if (auto it = sourceLinks->nth(hitIndex); it != sourceLinks->end()) {
+          const IndexSourceLink& sourceLink = *it;
+          auto geoId = sourceLink.geometryId();
+          trackSourceLinks.push_back(std::cref(sourceLink));
+          //surfSequence.push_back(m_cfg.trackingGeometry->findSurface(geoId));
+        } else {
+          ACTS_FATAL("Proto track " << itrack << " contains invalid hit index"
                                     << hitIndex);
           return StatusCode::FAILURE;
         }
-        trackSourceLinks.push_back(*sourceLink);
-        //surfSequence.push_back(m_cfg.trackingGeometry->findSurface(geoId));
       }
 
       if (msgLevel(MSG::DEBUG)) {
diff --git a/JugTrack/src/components/TrackFittingAlgorithm.h b/JugTrack/src/components/TrackFittingAlgorithm.h
index 33b5e446f4ebb538c6488681a58f61fd5666a047..2b4c312d5b87e81d12191d36dc4e2ce8be6a6a4f 100644
--- a/JugTrack/src/components/TrackFittingAlgorithm.h
+++ b/JugTrack/src/components/TrackFittingAlgorithm.h
@@ -43,20 +43,11 @@ namespace Jug::Reco {
   public:
     /// Track fitter function that takes input measurements, initial trackstate
     /// and fitter options and returns some track-fitter-specific result.
-    #if Acts_VERSION_MAJOR < 14
     using TrackFitterOptions =
-        Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder>;
-    #else
-    using TrackFitterOptions =
-        Acts::KalmanFitterOptions<
-            MeasurementCalibrator,
-            Acts::VoidOutlierFinder,
-            Acts::VoidReverseFilteringLogic
-        >;
-    #endif
+        Acts::KalmanFitterOptions;
 
     //using TrackFinderResult = Acts::Result<Acts::CombinatorialKalmanFilterResult<SourceLink>>;
-    using FitterResult = Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>;
+    using FitterResult = Acts::Result<Acts::KalmanFitterResult>;
 
     /// Fit function that takes input measurements, initial trackstate and fitter
     using FitterFunction = std::function<FitterResult(
diff --git a/JugTrack/src/components/TrackFittingFunction.cpp b/JugTrack/src/components/TrackFittingFunction.cpp
index 51ff3adf47deb57390a31a2cb396c81cefdef47d..1f2f7e801858aa3683d2a983bf2ac9ccf611defa 100644
--- a/JugTrack/src/components/TrackFittingFunction.cpp
+++ b/JugTrack/src/components/TrackFittingFunction.cpp
@@ -18,9 +18,9 @@ namespace {
   using Smoother         = Acts::GainMatrixSmoother;
   using Stepper          = Acts::EigenStepper<>;
   using Propagator       = Acts::Propagator<Stepper, Acts::Navigator>;
-  using Fitter           = Acts::KalmanFitter<Propagator, Updater, Smoother>;
+  using Fitter           = Acts::KalmanFitter<Propagator>;
   using DirectPropagator = Acts::Propagator<Stepper, Acts::DirectNavigator>;
-  using DirectFitter     = Acts::KalmanFitter<DirectPropagator, Updater, Smoother>;
+  using DirectFitter     = Acts::KalmanFitter<DirectPropagator>;
 
 
   /** Fitter implmentation .
@@ -38,36 +38,22 @@ namespace {
                const Jug::TrackParameters&                                 initialParameters,
                const Jug::Reco::TrackFittingAlgorithm::TrackFitterOptions& options) const
     {
-      return trackFitter.fit(sourceLinks, initialParameters, options);
+      return trackFitter.fit(sourceLinks.begin(), sourceLinks.end(), initialParameters, options);
     }
 
-    //TrackFittingAlgorithm::TrackFitterResult
-    //operator()(const std::vector<SourceLink>&              sourceLinks,
-    //           const TrackParameters&                           initialParameters,
-    //           const TrackFittingAlgorithm::TrackFitterOptions& options) const
-    //{
-    //  return trackFitter.fit(sourceLinks, initialParameters, options);
-    //};
   };
 
 }  // namespace
 
 namespace Jug::Reco {
 
-  //using InputMagneticField = typename std::decay_t<decltype(inputField)>::element_type;
-  //using MagneticField      = Acts::SharedBField<InputMagneticField>;
-  //using Stepper            = Acts::EigenStepper<MagneticField>;
-  //using Navigator          = Acts::Navigator;
-  //using Propagator         = Acts::Propagator<Stepper, Navigator>;
-  //using Fitter             = Acts::KalmanFitter<Propagator, Updater, Smoother>;
-
   using Updater          = Acts::GainMatrixUpdater;
   using Smoother         = Acts::GainMatrixSmoother;
   using Stepper          = Acts::EigenStepper<>;
   using Propagator       = Acts::Propagator<Stepper, Acts::Navigator>;
-  using Fitter           = Acts::KalmanFitter<Propagator, Updater, Smoother>;
+  using Fitter           = Acts::KalmanFitter<Propagator>;
   using DirectPropagator = Acts::Propagator<Stepper, Acts::DirectNavigator>;
-  using DirectFitter     = Acts::KalmanFitter<DirectPropagator, Updater, Smoother>;
+  using DirectFitter     = Acts::KalmanFitter<DirectPropagator>;
 
   TrackFittingAlgorithm::FitterFunction TrackFittingAlgorithm::makeTrackFittingFunction(
       std::shared_ptr<const Acts::TrackingGeometry>      trackingGeometry,
diff --git a/JugTrack/src/components/TrackerSourceLinker.cpp b/JugTrack/src/components/TrackerSourceLinker.cpp
index d835dc927a03254746b64ff384a28ce1a38d6630..2c8dbd1557ae5d116b6a8b3d03038eb692299760 100644
--- a/JugTrack/src/components/TrackerSourceLinker.cpp
+++ b/JugTrack/src/components/TrackerSourceLinker.cpp
@@ -43,6 +43,7 @@ namespace Jug::Reco {
   class TrackerSourceLinker : public GaudiAlgorithm {
   public:
     DataHandle<eic::TrackerHitCollection>    m_inputHitCollection{"inputHitCollection", Gaudi::DataHandle::Reader, this};
+    DataHandle<std::list<IndexSourceLink>>   m_sourceLinkStorage{"sourceLinkStorage", Gaudi::DataHandle::Writer, this};
     DataHandle<IndexSourceLinkContainer>     m_outputSourceLinks{"outputSourceLinks", Gaudi::DataHandle::Writer, this};
     DataHandle<MeasurementContainer>         m_outputMeasurements{"outputMeasurements", Gaudi::DataHandle::Writer, this};
     /// Pointer to the geometry service
@@ -52,7 +53,8 @@ namespace Jug::Reco {
     TrackerSourceLinker(const std::string& name, ISvcLocator* svcLoc)
         : GaudiAlgorithm(name, svcLoc) {
       declareProperty("inputHitCollection", m_inputHitCollection, "");
-      declareProperty("outputSourceLinks", m_outputSourceLinks, "");
+      declareProperty("sourceLinkStorage",  m_sourceLinkStorage, "");
+      declareProperty("outputSourceLinks",  m_outputSourceLinks, "");
       declareProperty("outputMeasurements", m_outputMeasurements, "");
     }
 
@@ -77,7 +79,8 @@ namespace Jug::Reco {
       // input collection
       const eic::TrackerHitCollection* hits = m_inputHitCollection.get();
       // Create output collections
-      auto sourceLinks = m_outputSourceLinks.createAndPut();
+      auto linkStorage  = m_sourceLinkStorage.createAndPut();
+      auto sourceLinks  = m_outputSourceLinks.createAndPut();
       auto measurements = m_outputMeasurements.createAndPut();
       sourceLinks->reserve(hits->size());
       measurements->reserve(hits->size());
@@ -135,12 +138,13 @@ namespace Jug::Reco {
         //
         // variable hitIdx not used anywhere
         //Index hitIdx = measurements->size();
-        IndexSourceLink sourceLink(surface->geometryId(), ihit);
+        linkStorage->emplace_back(surface->geometryId(), ihit);
+        IndexSourceLink& sourceLink = linkStorage->back();
         auto meas = Acts::makeMeasurement(sourceLink, loc, cov, Acts::eBoundLoc0, Acts::eBoundLoc1);
 
         // add to output containers. since the input is already geometry-order,
         // new elements in geometry containers can just be appended at the end.
-        sourceLinks->emplace_hint(sourceLinks->end(), std::move(sourceLink));
+        sourceLinks->emplace_hint(sourceLinks->end(), sourceLink);
         measurements->emplace_back(std::move(meas));
 
         ihit++;