diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
index 606cd86b1671d7ce7cb0337856be3b2bfb0641fc..6ba33a623fad21cce79d4de4a10620de2787d384 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
@@ -11,11 +11,8 @@
 
 #include <cassert>
 
-// TODO used for output, if output classes are ready this has to be changed
-#include "MeshLib/IO/writeMeshToFile.h"
-
-#include "ProcessLib/CalculateSurfaceFlux/CalculateSurfaceFlux.h"
-
+#include "ProcessLib/SurfaceFlux/SurfaceFlux.h"
+#include "ProcessLib/SurfaceFlux/SurfaceFluxData.h"
 #include "ProcessLib/Utils/CreateLocalAssemblers.h"
 
 namespace ProcessLib
@@ -33,16 +30,13 @@ ComponentTransportProcess::ComponentTransportProcess(
     SecondaryVariableCollection&& secondary_variables,
     NumLib::NamedFunctionCaller&& named_function_caller,
     bool const use_monolithic_scheme,
-    std::unique_ptr<MeshLib::Mesh>&& balance_mesh,
-    std::string&& balance_pv_name, std::string&& balance_out_fname)
+    std::unique_ptr<ProcessLib::SurfaceFluxData>&& surfaceflux)
     : Process(mesh, std::move(jacobian_assembler), parameters,
               integration_order, std::move(process_variables),
               std::move(secondary_variables), std::move(named_function_caller),
               use_monolithic_scheme),
       _process_data(std::move(process_data)),
-      _balance_mesh(std::move(balance_mesh)),
-      _balance_pv_name(std::move(balance_pv_name)),
-      _balance_out_fname(std::move(balance_out_fname))
+      _surfaceflux(std::move(surfaceflux))
 {
 }
 
@@ -130,32 +124,12 @@ void ComponentTransportProcess::postTimestepConcreteProcess(
             "ComponentTransportProcess.");
         return;
     }
-    if (!_balance_mesh)  // computing the balance is optional
+    if (!_surfaceflux)  // computing the surfaceflux is optional
     {
         return;
     }
-    auto* const balance_pv = MeshLib::getOrCreateMeshProperty<double>(
-        *_balance_mesh, _balance_pv_name, MeshLib::MeshItemType::Cell, 1);
-    // initialise the PropertyVector pv with zero values
-    std::fill(balance_pv->begin(), balance_pv->end(), 0.0);
-    auto balance = ProcessLib::CalculateSurfaceFlux(
-        *_balance_mesh,
-        getProcessVariables(process_id)[0].get().getNumberOfComponents(),
-        _integration_order);
-
-    balance.integrate(
-        x, *balance_pv, t, _mesh,
-        [this](std::size_t const element_id, MathLib::Point3d const& pnt,
-               double const t, GlobalVector const& x) {
-            return getFlux(element_id, pnt, t, x);
-        });
-    // post: surface_mesh has scalar element property
-
-    // TODO output, if output classes are ready this has to be
-    // changed
-    std::string const fname = BaseLib::dropFileExtension(_balance_out_fname) +
-                              "_t_" + std::to_string(t) + ".vtu";
-    MeshLib::IO::writeMeshToFile(*_balance_mesh, fname);
+    _surfaceflux->integrate(x, t, *this, process_id, _integration_order, _mesh);
+    _surfaceflux->save(t);
 }
 
 }  // namespace ComponentTransport
diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.h b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
index 9b805dc8c51b6df229bc7538c51c91b413eb1c71..78e6905f71974ff10454e874cfd2bf671a9a9439 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
@@ -16,6 +16,7 @@
 
 namespace ProcessLib
 {
+struct SurfaceFluxData;
 
 namespace ComponentTransport
 {
@@ -99,8 +100,7 @@ public:
         SecondaryVariableCollection&& secondary_variables,
         NumLib::NamedFunctionCaller&& named_function_caller,
         bool const use_monolithic_scheme,
-        std::unique_ptr<MeshLib::Mesh>&& balance_mesh,
-        std::string&& balance_pv_name, std::string&& balance_out_frame);
+        std::unique_ptr<ProcessLib::SurfaceFluxData>&& surfaceflux);
 
     //! \name ODESystem interface
     //! @{
@@ -137,9 +137,7 @@ private:
     std::vector<std::unique_ptr<ComponentTransportLocalAssemblerInterface>>
         _local_assemblers;
 
-    std::unique_ptr<MeshLib::Mesh> _balance_mesh;
-    std::string const _balance_pv_name;
-    std::string const _balance_out_fname;
+    std::unique_ptr<ProcessLib::SurfaceFluxData> _surfaceflux;
 };
 
 }  // namespace ComponentTransport
diff --git a/ProcessLib/ComponentTransport/CreateComponentTransportProcess.cpp b/ProcessLib/ComponentTransport/CreateComponentTransportProcess.cpp
index 0c1bdf1443146c2c4821b3099cceb1ce91b9af92..a5c3f2663c0f7e06b704b8457fad750925a297d5 100644
--- a/ProcessLib/ComponentTransport/CreateComponentTransportProcess.cpp
+++ b/ProcessLib/ComponentTransport/CreateComponentTransportProcess.cpp
@@ -14,7 +14,7 @@
 
 #include "MeshLib/IO/readMeshFromFile.h"
 
-#include "ProcessLib/CalculateSurfaceFlux/ParseCalculateSurfaceFluxData.h"
+#include "ProcessLib/SurfaceFlux/SurfaceFluxData.h"
 #include "ProcessLib/Output/CreateSecondaryVariables.h"
 #include "ProcessLib/Parameter/ConstantParameter.h"
 #include "ProcessLib/Utils/ProcessUtils.h"
@@ -170,44 +170,21 @@ std::unique_ptr<Process> createComponentTransportProcess(
     ProcessLib::createSecondaryVariables(config, secondary_variables,
                                          named_function_caller);
 
-    // for the balance
-    std::string balance_mesh_name; // surface mesh the balance will computed on
-    std::string balance_pv_name;
-    std::string balance_out_fname;
-    std::unique_ptr<MeshLib::Mesh> surface_mesh;
-    ProcessLib::parseCalculateSurfaceFluxData(
-        config, balance_mesh_name, balance_pv_name, balance_out_fname);
-
-    if (!mesh_name.empty())  // balance is optional
+    std::unique_ptr<ProcessLib::SurfaceFluxData> surfaceflux;
+    auto surfaceflux_config =
+        //! \ogs_file_param{prj__processes__process__calculatesurfaceflux}
+        config.getConfigSubtreeOptional("calculatesurfaceflux");
+    if (surfaceflux_config)
     {
-        // find the mesh for the specified mesh_name
-        auto balance_mesh = BaseLib::findElementOrError(
-            meshes.begin(), meshes.end(),
-            [&balance_mesh_name](auto const& m) {
-                return balance_mesh_name == m->getName();
-            },
-            "Expected to find o mesh named " + balance_mesh_name +
-                " for balance calculation.");
-
-        balance_out_fname =
-            BaseLib::copyPathToFileName(balance_out_fname, output_directory);
-
-        DBUG(
-            "read balance meta data:\n\tbalance mesh:\"%s\"\n\tproperty name: "
-            "\"%s\"\n\toutput to: \"%s\"",
-            balance_mesh_name.c_str(), balance_pv_name.c_str(),
-            balance_out_fname.c_str());
-
-        // Surface mesh and bulk mesh must have equal axial symmetry flags!
-        surface_mesh->setAxiallySymmetric(mesh.isAxiallySymmetric());
+        surfaceflux = ProcessLib::SurfaceFluxData::createSurfaceFluxData(
+            *surfaceflux_config, meshes, output_directory);
     }
 
     return std::make_unique<ComponentTransportProcess>(
         mesh, std::move(jacobian_assembler), parameters, integration_order,
         std::move(process_variables), std::move(process_data),
         std::move(secondary_variables), std::move(named_function_caller),
-        use_monolithic_scheme, std::move(surface_mesh),
-        std::move(balance_pv_name), std::move(balance_out_fname));
+        use_monolithic_scheme, std::move(surfaceflux));
 }
 
 }  // namespace ComponentTransport