diff --git a/core/config/CbmConfigBase.h b/core/config/CbmConfigBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..7129c88e6779e961f563d50beaeaf42c29604aa2
--- /dev/null
+++ b/core/config/CbmConfigBase.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#include "CbmDefs.h"
+
+#include <FairLogger.h>
+
+#include <TSystem.h>
+
+#include <boost/property_tree/json_parser.hpp>
+
+#include <cassert>
+#include <iostream>
+#include <map>
+#include <regex>
+
+namespace pt = boost::property_tree;
+
+template<class Config_t, class Obj_t>
+class CbmConfigBase {
+private:
+public:
+  using TagSet_t = std::set<std::string>;
+
+  virtual ~CbmConfigBase() = default;
+
+  static bool Load(Obj_t& obj, const std::string& path)
+  {
+    pt::ptree tree;
+    LoadFromFile(path, tree);
+    if (!Load(obj, tree)) return false;
+    return true;
+  }
+
+  static bool Load(Obj_t& obj, const pt::ptree& tree)
+  {
+    SetLogLevel(tree);
+    auto moduleTree {tree.get_child_optional(Config_t::GetModuleTag())};
+    if (!moduleTree) {
+      LOG(error) << "CbmConfig: module tag is not correct!\n";
+      return false;
+    }
+    if (!Validate(moduleTree.get())) return false;
+    if (!Config_t::LoadImpl(obj, moduleTree.get())) return false;
+    return true;
+  }
+
+  static void LoadFromFile(const std::string& path, pt::ptree& tree)
+  {
+    std::string absPath = path;
+    if (absPath.at(0) != '/') absPath = gSystem->GetWorkingDirectory() + "/" + path;
+    LOG(info) << "CbmConfig: loading config from file: " << absPath << std::endl;
+    pt::read_json(path, tree);
+  }
+
+  static bool Validate(const pt::ptree& tree)
+  {
+    const auto validationSet {Config_t::GetValidationTags()};
+    TagSet_t treeSet;
+    ParseTree(tree, "", treeSet);
+
+    std::vector<std::string> diff;
+    std::set_difference(treeSet.begin(), treeSet.end(), validationSet.begin(), validationSet.end(),
+                        std::inserter(diff, diff.begin()));
+
+    if (!diff.empty()) {
+      LOG(error) << "CbmConfig: Invalid tags: ";
+      for (auto s : diff)
+        std::cout << s << ", ";
+      std::cout << std::endl;
+      PrintAvailableTags();
+      return false;
+    }
+    return true;
+  }
+
+  static void ParseTree(const pt::ptree& pt, std::string key, TagSet_t& treeSet)
+  {
+    std::string nkey;
+
+    if (!key.empty()) {
+      nkey = key;
+      if (nkey.back() != '.') nkey += ".";
+      LOG(debug) << "CbmConfig: key: " << key << "\tnkey: " << nkey;
+    }
+
+    if (pt.empty() /* && !pt.data().empty()*/) {
+      if (key.back() == '.') key.pop_back();
+      LOG(debug) << "CbmConfig: Insert: " << key;
+      if (key.find("#") > key.size())  //used for comments
+        treeSet.insert(key);
+    }
+
+    for (auto node : pt) {
+      LOG(debug) << "CbmConfig: Try: " << nkey + node.first;
+      ParseTree(node.second, nkey + node.first, treeSet);
+    }
+  }
+
+  static void PrintAvailableTags()
+  {
+    auto tags = Config_t::GetValidationTags();
+    std::cout << "\nAvailable config tags:\n";
+    for (auto& tag : tags)
+      std::cout << tag << std::endl;
+  }
+
+  static ECbmModuleId stringToECbmModuleId(std::string s)
+  {
+    std::map<std::string, ECbmModuleId> stringToModuleId = {
+      {"cave", ECbmModuleId::kCave},     {"magnet", ECbmModuleId::kMagnet},    {"pipe", ECbmModuleId::kPipe},
+      {"target", ECbmModuleId::kTarget}, {"mvd", ECbmModuleId::kMvd},          {"sts", ECbmModuleId::kSts},
+      {"rich", ECbmModuleId::kRich},     {"much", ECbmModuleId::kMuch},        {"trd", ECbmModuleId::kTrd},
+      {"tof", ECbmModuleId::kTof},       {"psd", ECbmModuleId::kPsd},          {"hodo", ECbmModuleId::kHodo},
+      {"shield", ECbmModuleId::kShield}, {"platform", ECbmModuleId::kPlatform}};
+    if (stringToModuleId.find(s) == stringToModuleId.end()) {
+      LOG(error) << "CbmConfig: detector subsystem not recognized: " << s;
+      std::cout << "list of available detector subsystems:\n";
+      for (auto& p : stringToModuleId)
+        std::cout << p.first << std::endl;
+      assert(0);
+      return ECbmModuleId::kNotExist;
+    }
+    else
+      return stringToModuleId.at(s);
+  }
+
+  static std::string GetStringValue(boost::optional<std::string> opt) { return ParseString(opt.get()); }
+
+  static std::string GetStringValue(pt::ptree tree, std::string key, std::string fallback)
+  {
+    return ParseString(tree.get<std::string>(key, fallback));
+  }
+
+  static std::string ParseString(std::string s)
+  {
+    std::regex rgx("\\$\\{?\\w+\\}?");
+    std::smatch match;
+    while (s.find("$") < s.size()) {
+      std::regex_search(s, match, rgx);
+      std::string varString = match[0];
+      std::string varName   = std::regex_replace(varString, std::regex("\\$|\\{|\\}"), "");
+      s.replace(s.find(varString), varString.size(), gSystem->Getenv(varName.c_str()));
+    }
+    return s;
+  }
+
+  static void SetLogLevel(const pt::ptree& moduleTree)
+  {
+    auto logScreenLevel = moduleTree.get_optional<std::string>("logScreenLevel");
+    if (logScreenLevel) FairLogger::GetLogger()->SetLogScreenLevel(logScreenLevel.get().c_str());
+    auto logVerbosityLevel = moduleTree.get_optional<std::string>("logVerbosityLevel");
+    if (logVerbosityLevel) FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosityLevel.get().c_str());
+  }
+};
diff --git a/macro/run/CMakeLists.txt b/macro/run/CMakeLists.txt
index 26f834b8880e5a070ba7dd1d6a2c29eb56023434..6877a0887318bde5cbb71f9a175cd075c76776cc 100644
--- a/macro/run/CMakeLists.txt
+++ b/macro/run/CMakeLists.txt
@@ -1,5 +1,7 @@
 # =====   Generate the needed shell scripts   ================================
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_file.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_transport_json_config.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi_json_config.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_beam.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi.C)
 GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_reco.C)
@@ -108,6 +110,30 @@ foreach(setup IN LISTS cbm_setup)
   	RESOURCE_LOCK beamParDb_${setup}
   )
 
+  # --- Test run_transport_json_config
+  # --- Transport run using run_transport_json_config.C
+  set(testname run_transport_json_config)
+  add_test(${testname} ${MACRO_DIR}/run_transport_json_config.sh)
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+  	FIXTURES_REQUIRED cleanup
+  	FIXTURES_SETUP fixt_digi_json_config
+  	RESOURCE_LOCK json_config_ParDb
+  )
+
+  # --- Test run_digi_json_config
+  # --- Digitization run with using run_digi_json_config.C
+  set(testname run_digi_json_config)
+  add_test(${testname} ${MACRO_DIR}/run_digi_json_config.sh)
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+  	FIXTURES_REQUIRED fixt_digi_json_config
+  	FIXTURES_SETUP fixt_reco_json_config
+  	RESOURCE_LOCK json_config_ParDb
+  )
+
   # --- Test run_digi_ev
   # --- Detector response simulation, event-by-event, using run_digi.C
   set(testname run_${sname}_digi_ev)
@@ -209,7 +235,7 @@ endforeach(setup IN LISTS cbm_setup)
 
 
 
-Install(FILES .rootrc run_transport.C run_digi.C run_reco_event.C check_overlaps.C
+Install(FILES .rootrc run_transport.C run_transport_json_config.C run_digi_json_config.C config.json run_digi.C run_reco_event.C check_overlaps.C
         DESTINATION share/cbmroot/macro/run
        )
 Install(DIRECTORY modules DESTINATION share/cbmroot/macro/run)
diff --git a/macro/run/config.json b/macro/run/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..136720decf09e25bee97698bb8384c6e1b8b9fb2
--- /dev/null
+++ b/macro/run/config.json
@@ -0,0 +1,109 @@
+{
+  "logScreenLevel": "INFO",
+  "logVerbosityLevel": "LOW",
+  "transport": {
+    "input": [
+      {"generator": "unigen",
+       "file": "${VMCWORKDIR}/input/urqmd.auau.10gev.centr.root"},
+      {"generator": "pluto",
+       "file": "${VMCWORKDIR}/input/pluto.auau.8gev.omega.mpmm.0001.root",
+       "plutoPdg": 0},
+      {"generator": "beam",
+       "beamA": 197,
+       "beamZ": 79,
+       "beamQ": 79,
+       "beamP": 12.0,
+       "beamStartZ": -1.0}
+    ],
+    "output.path": "",
+    "target": {
+      "material": "Gold",
+      "thickness": 0.025,
+      "diameter": 2.5,
+      "position": {
+        "x": 0.0,
+        "y": 0.0,
+        "z": 0.0
+      },
+      "rotation.y": 0.0
+    },
+    "beam": {
+      "position": {
+        "x": 0.0,
+        "y": 0.0,
+        "z": 0.0,
+        "sigmaX": 0.1,
+        "sigmaY": 0.1
+      },
+      "angle": {
+        "x": 0.0,
+        "y": 0.0,
+        "sigmaX": 0.001,
+        "sigmaY": 0.001
+      }
+    },
+    "randomRP": true,
+    "geantVersion": 4,
+    "geant4vmcSettings": {
+      "physicsLists": "QGSP_BERT_EMV+optical",
+      "specialProcesses": "stepLimiter",
+      "maxNsteps": 10000000,
+      "geant4commands": [""]
+    },
+    "geometry": {
+      "baseSetup": "sis100_electron",
+      "magneticField": {
+        "tag": "v18a",
+        "scale": 1.0,
+        "position": {
+          "x": 0.0,
+          "y": 0.0,
+          "z": 40.0
+        }
+      },
+      "subsystems": {
+        "magnet":   "v20a",
+        "pipe":     "v16b_1e",
+        "mvd":      "v20c_tr",
+        "sts":      "v19a",
+        "rich":     "v17a_1e",
+        "trd":      "v20b_1e",
+        "tof":      "v20a_1e",
+        "psd":      "v20a",
+        "platform": "v13a"
+      }
+    }
+  },
+  
+  "digitization": {
+    "generateRunInfo": false,
+    "eventMode": false,
+    "timeSliceLength": -1.0,
+    "storeAllTimeSlices": false,
+    "startTime": 1000,
+    "produceNoise": true,
+    "input": [
+      {"id": 0,
+       "path": "test",
+       "rate": "1.e7",
+       "treeAccessMode": "regular",
+       "parameterSource": true},
+      {"id": -1,
+       "path": "test_emb",
+       "embedToId": 0,
+       "treeAccessMode": "regular"},
+      {"id": -1,
+       "path": "test_beam",
+       "rate": "1.e9",
+       "treeAccessMode": "random"}
+    ],
+    "output": {
+      "path": "test",
+      "overwrite": false
+    },
+    "geometry": {
+      "deactivate": ["", ""],
+      "#deactivateAllBut": ""
+    }
+  } 
+}
diff --git a/macro/run/run_digi_json_config.C b/macro/run/run_digi_json_config.C
new file mode 100644
index 0000000000000000000000000000000000000000..df7ab5b6df25e16ea26a4480bc9440be4d90f3b2
--- /dev/null
+++ b/macro/run/run_digi_json_config.C
@@ -0,0 +1,58 @@
+/** @file run_digi_json_config.C
+ ** @author Oleg Golosov <oleg.golosov@gmail.com>
+ ** @since 31 March 2020
+ **/
+
+// Includes needed for IDE
+#if !defined(__CLING__)
+#include "CbmDigitization.h"
+
+#include "FairSystemInfo.h"
+
+#include "TStopwatch.h"
+#endif
+
+
+/** @brief Macro for detector response simulation in CBM
+ ** @author Oleg Golosov <oleg.golosov@gmail.com>
+ ** @since  31 March 2021
+ ** @param config      Name of config file
+ ** @param nEvents     Number of events to process
+ **
+ ** This macro performs the detector response simulation
+ ** for multiple transport files using test-based config.
+ ** Additions to the CbmDigitization settings can be made after
+ ** the main config is applied. 
+ **/
+
+void run_digi_json_config(std::string config = "", int nEvents = 2)
+{
+  if (config == "") config = Form("%s/macro/run/config.json", gSystem->Getenv("VMCWORKDIR"));
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  CbmDigitization run;
+  if (CbmDigitizationConfig::Load(run, config)) run.Run(nEvents);
+  else
+    return;
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << std::endl;
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
+  Float_t cpuUsage = ctime / rtime;
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
+}
diff --git a/macro/run/run_transport_json_config.C b/macro/run/run_transport_json_config.C
new file mode 100644
index 0000000000000000000000000000000000000000..d8af8231f0e13e9d01ea11fd65ed1084e22d24f6
--- /dev/null
+++ b/macro/run/run_transport_json_config.C
@@ -0,0 +1,58 @@
+/** @file run_transport_json_config.C
+ ** @author Oleg Golosov <oleg.golosov@gmail.com>
+ ** @since 31 March 2020
+ **/
+
+// Includes needed for IDE
+#if !defined(__CLING__)
+#include "CbmTransport.h"
+
+#include "FairSystemInfo.h"
+
+#include "TStopwatch.h"
+#endif
+
+
+/** @brief Macro for transport simulation of events from file
+ ** @author Oleg Golosov <oleg.golosov@gmail.com>
+ ** @since  31 March 2021
+ ** @param config      Name of config file
+ ** @param nEvents     Number of events to transport
+ **
+ ** This macro performs the transport simulation of externally generated
+ ** events from an input file using test-based config.
+ ** Additions to the CbmTransport settings can be made after
+ ** the main config is applied. 
+ **/
+
+void run_transport_json_config(std::string config = "", int nEvents = 2)
+{
+  if (config == "") config = Form("%s/macro/run/config.json", gSystem->Getenv("VMCWORKDIR"));
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  CbmTransport run;
+  if (CbmTransportConfig::Load(run, config)) run.Run(nEvents);
+  else
+    return;
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << std::endl;
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
+  Float_t cpuUsage = ctime / rtime;
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
+}
diff --git a/sim/response/CMakeLists.txt b/sim/response/CMakeLists.txt
index 45a76c11f85e7828f979c8806a22ffb865d8cef2..7c9e4ec40e83bd0151d9aef9d3ae7a5f9e41b8de 100644
--- a/sim/response/CMakeLists.txt
+++ b/sim/response/CMakeLists.txt
@@ -14,12 +14,15 @@ base/CbmDigitizeInfo.cxx
 base/CbmMCInput.cxx
 base/CbmMCInputSet.cxx
 base/CbmRunAna.cxx
+base/CbmDigitizationConfig.cxx
 )
 # ---------------------------------------------------------
 
 
 # ----  Include directories -------------------------------
 set(INCLUDE_DIRECTORIES
+${CBMROOT_SOURCE_DIR}/core/config
+
 ${CBMROOT_SOURCE_DIR}/sim/response
 ${CBMROOT_SOURCE_DIR}/sim/response/base
 
diff --git a/sim/response/CbmSimResponseLinkDef.h b/sim/response/CbmSimResponseLinkDef.h
index 5d3c66a616ecc068ff8c6a99eac06bfefb95ada8..d62fa29ff68faea0e4e400af33d5b106e6cafd81 100644
--- a/sim/response/CbmSimResponseLinkDef.h
+++ b/sim/response/CbmSimResponseLinkDef.h
@@ -6,6 +6,7 @@
 
 // --- base
 #pragma link C++ class CbmDigitization + ;
+#pragma link C++ class CbmDigitizationConfig + ;
 #pragma link C++ class CbmDigitizationSource + ;
 #pragma link C++ class CbmDigitizeInfo + ;
 #pragma link C++ class CbmMCInput + ;
diff --git a/sim/response/base/CbmDigitizationConfig.cxx b/sim/response/base/CbmDigitizationConfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..37e5a2db1e07077c9720261c51b6ca45bcc3eb51
--- /dev/null
+++ b/sim/response/base/CbmDigitizationConfig.cxx
@@ -0,0 +1,163 @@
+#include "CbmDigitizationConfig.h"
+
+#include "CbmDigitization.h"
+
+using namespace std;
+
+string CbmDigitizationConfig::GetModuleTag() { return "digitization"; }
+
+CbmDigitizationConfig::TagSet_t CbmDigitizationConfig::GetValidationTags()
+{
+  return {"logScreenLevel",
+          "logVerbosityLevel",
+          "generateRunInfo",
+          "storeAllTimeSlices",
+          "eventMode",
+          "startTime",
+          "timeSliceLength",
+          "produceNoise",
+          "input.id",
+          "input.path",
+          "input.rate",
+          "input.embedToId",
+          "input.treeAccessMode",
+          "input.parameterSource",
+          "output.overwrite",
+          "output.path",
+          "geometry.path",
+          "geometry.sourceId",
+          "geometry.deactivate",
+          "geometry.deactivateAllBut"};
+}
+
+bool CbmDigitizationConfig::SetIO(CbmDigitization& obj, const pt::ptree& moduleTree)
+{
+  map<string, ECbmTreeAccess> stringToECbmTreeAccess = {{"regular", ECbmTreeAccess::kRegular},
+                                                        {"repeat", ECbmTreeAccess::kRepeat},
+                                                        {"random", ECbmTreeAccess::kRandom}};
+  bool eventMode                                     = moduleTree.get<bool>("eventMode", false);
+  auto inputs                                        = moduleTree.get_child("input");
+  uint inputCounter                                  = 0;
+  vector<string> paths;
+  bool parametersSet    = false;
+  string parametersPath = "";
+  ECbmTreeAccess treeAccessMode;
+  for (auto& input : inputs) {
+    pt::ptree pt_input          = input.second;
+    int id                      = pt_input.get<int>("id", inputCounter);
+    string path                 = GetStringValue(pt_input, "path", "");
+    auto configRate             = pt_input.get_optional<float>("rate");
+    string treeAccessModeString = pt_input.get<string>("treeAccessMode", "regular");
+    bool parameterSource        = pt_input.get<bool>("parameterSource", false);
+    auto configEmbedToId        = pt_input.get_optional<int>("embedToId");
+
+    if (id < 0) continue;
+    if (path == "") {
+      LOG(error) << "CbmDigitizationConfig: no path specified for input #" << id;
+      return false;
+    }
+    paths.push_back(path);
+    string traFileName = path + ".tra.root";
+    if (stringToECbmTreeAccess.find(treeAccessModeString) != stringToECbmTreeAccess.end())
+      treeAccessMode = stringToECbmTreeAccess.at(treeAccessModeString);
+    else {
+      LOG(error) << "CbmDigitizationConfig: invalid tree access mode: " << treeAccessModeString;
+      cout << "Available access modes:\n";
+      for (auto& p : stringToECbmTreeAccess)
+        cout << p.first << endl;
+      return false;
+    }
+
+    if (configEmbedToId) {
+      if (configRate) {
+        LOG(error) << "CbmDigitizationConfig: input.embedToId and input.rate should not be used simultaneously!";
+        return false;
+      }
+      else {
+        int embedToId = configEmbedToId.get();
+        LOG(info) << "CbmDigitizationConfig: Embedding input: " << traFileName;
+        obj.EmbedInput(id, traFileName, embedToId);
+      }
+    }
+    else {
+      if (eventMode && inputCounter > 0) {
+        LOG(error) << "CbmDigitizationConfig: event mixing is not possible in event-by-event mode!";
+        return false;
+      }
+      float rate = pt_input.get<float>("rate", -1.);
+      LOG(info) << "CbmDigitizationConfig: Adding input: " << traFileName;
+      obj.AddInput(id, path + ".tra.root", rate, treeAccessMode);
+    }
+    if (parameterSource) {
+      if (!parametersSet) { parametersPath = path; }
+      else {
+        LOG(error) << "CbmDigitizationConfig: only one parameter source is allowed!";
+        return false;
+      }
+    }
+    inputCounter++;
+  }
+
+  string outputPath = GetStringValue(moduleTree, "output.path", paths.at(0));
+  bool overwrite    = moduleTree.get<bool>("output.overwrite", false);
+
+  if (!parametersSet) parametersPath = paths.at(0);
+  LOG(info) << "CbmDigitizationConfig: Parameter source:\n" << parametersPath;
+  obj.SetParameterRootFile(parametersPath + ".par.root");
+  LOG(info) << "CbmDigitizationConfig: Output path:\n" << outputPath;
+  obj.SetOutputFile(outputPath + ".raw.root", overwrite);
+  obj.SetMonitorFile((outputPath + ".moni_digi.root").c_str());
+
+  return true;
+}
+
+bool CbmDigitizationConfig::SetDigitizationParameters(CbmDigitization& obj, const pt::ptree& moduleTree)
+{
+
+  auto produceNoise       = moduleTree.get_optional<bool>("produceNoise");
+  bool eventMode          = moduleTree.get<bool>("eventMode", false);
+  auto storeAllTimeSlices = moduleTree.get_optional<bool>("storeAllTimeSlices");
+  auto timeSliceLength    = moduleTree.get_optional<float>("timeSliceLength");
+  auto startTime          = moduleTree.get_optional<float>("startTime");
+
+  if (eventMode) {
+    if (storeAllTimeSlices || timeSliceLength || startTime) {
+      LOG(error) << "CbmDigitizationConfig: time slice settings should not be used in event mode!";
+      return false;
+    }
+  }
+  obj.SetEventMode(eventMode);
+
+  if (timeSliceLength) obj.SetTimeSliceLength(timeSliceLength.get());
+  if (startTime) obj.SetStartTime(startTime.get());
+  if (produceNoise) obj.SetProduceNoise(produceNoise.get());
+  return true;
+}
+
+bool CbmDigitizationConfig::SetGeometry(CbmDigitization& obj, const pt::ptree& moduleTree)
+{
+  auto modulesToDeactivate = moduleTree.get_child_optional("geometry.deactivate");
+  auto deactivateAllBut    = moduleTree.get_optional<string>("geometry.deactivateAllBut");
+
+  if (modulesToDeactivate && deactivateAllBut) {
+    LOG(error)
+      << "CbmDigitizationConfig: geometry.deactivate and geometry.deactivateAllBut should not be used simultaneously!";
+    return false;
+  }
+
+  if (deactivateAllBut && deactivateAllBut.get() != "")
+    obj.DeactivateAllBut(stringToECbmModuleId(deactivateAllBut.get()));
+
+  if (modulesToDeactivate)
+    for (auto& module : modulesToDeactivate.get())
+      if (module.first != "") obj.Deactivate(stringToECbmModuleId(module.first));
+
+  return true;
+}
+
+bool CbmDigitizationConfig::LoadImpl(CbmDigitization& obj, const pt::ptree& moduleTree)
+{
+  return SetIO(obj, moduleTree) && SetDigitizationParameters(obj, moduleTree) && SetGeometry(obj, moduleTree);
+}
+
+ClassImp(CbmDigitizationConfig)
diff --git a/sim/response/base/CbmDigitizationConfig.h b/sim/response/base/CbmDigitizationConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d96f6ea1d5c87e8bba84181ea848c2fd620dcc5
--- /dev/null
+++ b/sim/response/base/CbmDigitizationConfig.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "CbmConfigBase.h"
+
+class CbmDigitization;
+
+class CbmDigitizationConfig : public CbmConfigBase<CbmDigitizationConfig, CbmDigitization> {
+
+public:
+  using TagSet_t = CbmConfigBase<CbmDigitizationConfig, CbmDigitization>::TagSet_t;
+
+  static std::string GetModuleTag();
+  static TagSet_t GetValidationTags();
+  static bool LoadImpl(CbmDigitization& obj, const pt::ptree& moduleTree);
+  static bool SetIO(CbmDigitization& obj, const pt::ptree& moduleTree);
+  static bool SetDigitizationParameters(CbmDigitization& obj, const pt::ptree& moduleTree);
+  static bool SetGeometry(CbmDigitization& obj, const pt::ptree& moduleTree);
+
+  ClassDef(CbmDigitizationConfig, 1);
+};
+
+//#endif
diff --git a/sim/transport/steer/CMakeLists.txt b/sim/transport/steer/CMakeLists.txt
index 375b40e617e1003f3a1220ccc95de52cf75db82a..14620992b9ff790dfa465f9a13f557d37ac9f556 100644
--- a/sim/transport/steer/CMakeLists.txt
+++ b/sim/transport/steer/CMakeLists.txt
@@ -13,6 +13,7 @@ CbmTransport.cxx
 CbmVMCSettings.cxx
 CbmGeant3Settings.cxx
 CbmGeant4Settings.cxx
+CbmTransportConfig.cxx
 )
 # ---------------------------------------------------------
 
@@ -34,6 +35,7 @@ ${CBMROOT_SOURCE_DIR}/sim/transport/steer
 ${CBMROOT_SOURCE_DIR}/sim/transport/geosetup
 ${CBMDATA_DIR}
 ${CBMBASE_DIR}/utils
+${CBMROOT_SOURCE_DIR}/core/config
 )
 
 set(SYSTEM_INCLUDE_DIRECTORIES
diff --git a/sim/transport/steer/CbmSimSteerLinkDef.h b/sim/transport/steer/CbmSimSteerLinkDef.h
index 51f4426add2e553eb8646a5b889493fb46820074..ac2669aed43a32100aa0d6d59daba9f9f5b13477 100644
--- a/sim/transport/steer/CbmSimSteerLinkDef.h
+++ b/sim/transport/steer/CbmSimSteerLinkDef.h
@@ -10,6 +10,7 @@
 #pragma link C++ class CbmVMCSettings + ;
 #pragma link C++ class CbmGeant3Settings + ;
 #pragma link C++ class CbmGeant4Settings + ;
+#pragma link C++ class CbmTransportConfig + ;
 #pragma link C++ enum ECbmEngine;
 
 
diff --git a/sim/transport/steer/CbmTransportConfig.cxx b/sim/transport/steer/CbmTransportConfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4042f16c0437b3780a630e81d6c0c483cd597cee
--- /dev/null
+++ b/sim/transport/steer/CbmTransportConfig.cxx
@@ -0,0 +1,306 @@
+#include "CbmTransportConfig.h"
+
+#include "CbmBeamGenerator.h"
+#include "CbmGeant4Settings.h"
+#include "CbmPlutoGenerator.h"
+#include "CbmTransport.h"
+
+using namespace std;
+
+string CbmTransportConfig::GetModuleTag() { return "transport"; }
+
+CbmTransportConfig::TagSet_t CbmTransportConfig::GetValidationTags()
+{
+  return {"logScreenLevel",
+          "logVerbosityLevel",
+          "input.file",
+          "input.generator",
+          "input.plutoPdg",
+          "input.beamA",
+          "input.beamZ",
+          "input.beamQ",
+          "input.beamP",
+          "input.beamStartZ",
+          "output.path",
+          "target.material",
+          "target.thickness",
+          "target.diameter",
+          "target.position.x",
+          "target.position.y",
+          "target.position.z",
+          "target.rotation.y",
+          "beam.position.x",
+          "beam.position.y",
+          "beam.position.z",
+          "beam.position.sigmaX",
+          "beam.position.sigmaY",
+          "beam.angle.x",
+          "beam.angle.y",
+          "beam.angle.sigmaX",
+          "beam.angle.sigmaY",
+          "geantVersion",
+          "geant4vmcSettings.physicsLists",
+          "geant4vmcSettings.specialProcesses",
+          "geant4vmcSettings.maxNsteps",
+          "geant4vmcSettings.geant4commands",
+          "randomRP",
+          "geometry.magneticField.position.x",
+          "geometry.magneticField.position.y",
+          "geometry.magneticField.position.z",
+          "geometry.magneticField.scale",
+          "geometry.magneticField.tag",
+          "geometry.baseSetup",
+          "geometry.subsystems",
+          "geometry.subsystems.cave",
+          "geometry.subsystems.magnet",
+          "geometry.subsystems.pipe",
+          "geometry.subsystems.target",
+          "geometry.subsystems.mvd",
+          "geometry.subsystems.sts",
+          "geometry.subsystems.rich",
+          "geometry.subsystems.much",
+          "geometry.subsystems.trd",
+          "geometry.subsystems.tof",
+          "geometry.subsystems.psd",
+          "geometry.subsystems.hodo",
+          "geometry.subsystems.shield",
+          "geometry.subsystems.platform"};
+}
+
+CbmTransportConfig::TagSet_t CbmTransportConfig::GetAcceptedGenerators() { return {"unigen", "pluto", "beam"}; }
+
+bool CbmTransportConfig::SetIO(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  auto inputs      = moduleTree.get_child("input");
+  int inputCounter = 0;
+  for (auto& input : inputs) {
+    pt::ptree pt_input    = input.second;
+    string inputGenerator = pt_input.get<string>("generator", "unigen");
+    string inputFile      = GetStringValue(pt_input, "file", "");
+
+    if (inputFile == "") { LOG(error) << "CbmTransportConfig: no input path specified for input #" << inputCounter; }
+
+    if (inputGenerator == "unigen") obj.AddInput(inputFile.c_str(), kUnigen);
+    else if (inputGenerator == "pluto") {
+      auto plutoGen  = new CbmPlutoGenerator(inputFile.c_str());
+      auto manualPdg = pt_input.get_optional<int>("plutoPdg");
+      if (manualPdg) plutoGen->SetManualPDG(manualPdg.get());
+      obj.AddInput(plutoGen);
+    }
+    else if (inputGenerator == "beam") {
+      auto confBeamA      = pt_input.get_optional<int>("beamA");
+      auto confBeamZ      = pt_input.get_optional<int>("beamZ");
+      auto confBeamQ      = pt_input.get_optional<int>("beamQ");
+      auto confBeamP      = pt_input.get_optional<float>("beamP");
+      auto confBeamStartZ = pt_input.get_optional<float>("beamStartZ");
+      auto targetZ        = moduleTree.get_optional<float>("target.position.z");
+      int beamA, beamZ, beamQ;
+      float beamP, beamStartZ;
+      if (confBeamA && confBeamZ && confBeamP) {
+        beamA = confBeamA.get();
+        beamZ = confBeamZ.get();
+        beamP = confBeamP.get();
+        if (confBeamQ) beamQ = confBeamQ.get();
+        else
+          beamQ = confBeamA.get();
+        if (confBeamStartZ) beamStartZ = confBeamStartZ.get();
+        else if (targetZ) {
+          beamStartZ = targetZ.get() - 1.;
+          LOG(warning) << "CbmTransportConfig: beamStartZ=targetZ-1. cm";
+        }
+        else {
+          LOG(error) << "CbmTransportConfig: beam start Z not set!";
+          return false;
+        }
+        obj.AddInput(new CbmBeamGenerator(beamZ, beamA, beamQ, beamP, beamStartZ));
+        LOG(info) << Form("CbmTransportConfig: add beam generator: Z = %d, A = %d, Q = %d, P = %f, startZ = %f", beamZ,
+                          beamA, beamQ, beamP, beamStartZ);
+      }
+      else {
+        LOG(error) << "CbmTransportConfig: Incomplete beam generator configuration: A, Z and P required!";
+        return false;
+      }
+    }
+    else {
+      LOG(error) << "CbmTransportConfig: Unknown generator type " << inputGenerator << endl
+                 << "Accepted generator types:";
+      for (auto& gen : GetAcceptedGenerators())
+        cout << gen << ", ";
+      cout << endl;
+      return false;
+    }
+    inputCounter++;
+  }
+
+  string outputPath = GetStringValue(moduleTree, "output.path", "test");
+  LOG(info) << "CbmTransportConfig: Output path: " << outputPath;
+  obj.SetOutFileName(outputPath + ".tra.root");
+  obj.SetParFileName(outputPath + ".par.root");
+  obj.SetGeoFileName(outputPath + ".geo.root");
+
+  return true;
+}
+
+bool CbmTransportConfig::SetTarget(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  auto material  = moduleTree.get_optional<string>("target.material");
+  auto thickness = moduleTree.get_optional<float>("target.thickness");
+  auto diameter  = moduleTree.get_optional<float>("target.diameter");
+  auto x         = moduleTree.get_optional<float>("target.position.x");
+  auto y         = moduleTree.get_optional<float>("target.position.y");
+  auto z         = moduleTree.get_optional<float>("target.position.z");
+  auto rotY      = moduleTree.get_optional<float>("target.rotation.y");
+  // one can set a target only if all 3 parameters are present in config file
+  if (material && thickness && diameter) {
+    if (x && y && z && rotY)
+      obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get(), z.get(), rotY.get());
+    else if (x && y && z)
+      obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get(), z.get());
+    else if (x && y)
+      obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get());
+    else if (x)
+      obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get());
+    else
+      obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get());
+  }
+  else {
+    LOG(error) << "CbmTransportConfig: Incomplete target configuration (material, thickness and diameter required)\n";
+    return false;
+  }
+  return true;
+}
+
+bool CbmTransportConfig::SetBeamProfile(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  auto posX      = moduleTree.get_optional<float>("beam.position.x");
+  auto posY      = moduleTree.get_optional<float>("beam.position.y");
+  auto posZ      = moduleTree.get_optional<float>("beam.position.z");
+  auto posSigmaX = moduleTree.get_optional<float>("beam.position.sigmaX");
+  auto posSigmaY = moduleTree.get_optional<float>("beam.position.sigmaY");
+  if (posX && posY) {
+    if (posSigmaX && posSigmaY && posZ)
+      obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get(), posSigmaY.get(), posZ.get());
+    else if (posSigmaX && posSigmaY)
+      obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get(), posSigmaY.get());
+    else if (posSigmaX)
+      obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get());
+    else if (posX && posY)
+      obj.SetBeamPosition(posX.get(), posY.get());
+  }
+  else {
+    LOG(error) << "CbmTransportConfig: Incomplete beam position configuration (x and y required)\n";
+    return false;
+  }
+  auto angX      = moduleTree.get_optional<float>("beam.angle.x");
+  auto angY      = moduleTree.get_optional<float>("beam.angle.y");
+  auto angSigmaX = moduleTree.get_optional<float>("beam.angle.sigmaX");
+  auto angSigmaY = moduleTree.get_optional<float>("beam.angle.sigmaY");
+  if (angX && angY) {
+    if (angSigmaX && angSigmaY) obj.SetBeamAngle(angX.get(), angY.get(), angSigmaX.get(), angSigmaY.get());
+    else if (angSigmaX)
+      obj.SetBeamAngle(angX.get(), angY.get(), angSigmaX.get());
+    else if (angX && angY)
+      obj.SetBeamAngle(angX.get(), angY.get());
+  }
+  else {
+    LOG(error) << "CbmTransportConfig: Incomplete beam angle configuration (x and y required)\n";
+    return false;
+  }
+  return true;
+}
+
+bool CbmTransportConfig::SetTransportParameters(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  bool randomRP       = true;
+  auto configRandomRP = moduleTree.get_optional<float>("randomRP");
+  if (configRandomRP) randomRP = configRandomRP.get();
+  if (randomRP) obj.SetRandomEventPlane();
+
+  ECbmEngine engine = kGeant3;
+  auto geantVersion = moduleTree.get_optional<float>("geantVersion");
+  if (geantVersion) {
+    if (geantVersion.get() == 4) engine = kGeant4;
+    else if (geantVersion.get() != 3) {
+      LOG(error) << "CbmTransportConfig: Unknown Geant version: " << geantVersion.get();
+      return false;
+    }
+  }
+  obj.SetEngine(engine);
+
+  if (engine == kGeant4) {
+    auto g4settings = moduleTree.get_child_optional("geant4vmcSettings");
+    if (g4settings) {
+      auto g4settingsTree   = g4settings.get();
+      auto physicsLists     = g4settingsTree.get_optional<string>("physicsLists");
+      auto specialProcesses = g4settingsTree.get_optional<string>("specialProcesses");
+      auto maxNsteps        = g4settingsTree.get_optional<int>("maxNsteps");
+
+      CbmGeant4Settings* settings = new CbmGeant4Settings();
+
+      if ((physicsLists && !specialProcesses) || (!physicsLists && specialProcesses)) {
+        LOG(error)
+          << "CbmTransportConfig: Incomplete Geant4 configuration: physicsLists and specialProcesses required!";
+        return false;
+      }
+      else if (physicsLists && specialProcesses)
+        settings->SetG4RunConfig("geomRoot", physicsLists.get(), specialProcesses.get());
+
+      if (maxNsteps) settings->SetMaximumNumberOfSteps(maxNsteps.get());
+
+      auto g4commands = g4settingsTree.get_child_optional("geant4commands");
+      if (g4commands)
+        for (auto& command : g4commands.get())
+          settings->AddG4Command(command.second.data());
+      settings->Dump();
+      obj.SetGeant4Settings(settings);
+    }
+  }
+  return true;
+}
+
+bool CbmTransportConfig::SetGeometry(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  auto geometry = moduleTree.get_child_optional("geometry");
+  if (!geometry) {
+    LOG(error) << "CbmTransportConfig: geometry settings missing!";
+    return false;
+  }
+  auto geometryTree = geometry.get();
+  auto baseSetup    = geometryTree.get_optional<string>("baseSetup");
+  if (baseSetup) obj.LoadSetup(baseSetup.get().c_str());
+
+  auto setup      = obj.GetSetup();
+  auto fieldTag   = geometryTree.get_optional<string>("magneticField.tag");
+  auto fieldScale = geometryTree.get_optional<float>("magneticField.scale");
+  auto fieldX     = geometryTree.get_optional<float>("magneticField.position.x");
+  auto fieldY     = geometryTree.get_optional<float>("magneticField.position.y");
+  auto fieldZ     = geometryTree.get_optional<float>("magneticField.position.z");
+
+  if (fieldTag && fieldScale && fieldX && fieldY && fieldZ)
+    setup->SetField(fieldTag.get().c_str(), fieldScale.get(), fieldX.get(), fieldY.get(), fieldZ.get());
+  else if (fieldScale) {
+    if (baseSetup) setup->SetFieldScale(fieldScale.get());
+    else {
+      LOG(error) << "CbmTransportConfig: Incomplete magnetic field configuration: fieldTag, fieldScale, fieldX, fieldY "
+                    "and fieldZ are required if base setup is not defined!";
+      return false;
+    }
+  }
+  auto modules = geometryTree.get_child_optional("subsystems");
+  if (modules)
+    for (auto& module : modules.get()) {
+      auto moduleId = stringToECbmModuleId(module.first);
+      if (module.second.data() == "") setup->RemoveModule(moduleId);
+      else
+        setup->SetModule(moduleId, module.second.data().c_str());
+    }
+  return true;
+}
+
+bool CbmTransportConfig::LoadImpl(CbmTransport& obj, const pt::ptree& moduleTree)
+{
+  return SetIO(obj, moduleTree) && SetTarget(obj, moduleTree) && SetBeamProfile(obj, moduleTree)
+         && SetTransportParameters(obj, moduleTree) && SetGeometry(obj, moduleTree);
+}
+
+ClassImp(CbmTransportConfig)
diff --git a/sim/transport/steer/CbmTransportConfig.h b/sim/transport/steer/CbmTransportConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c15558b683427ade4d63b9430c281a7b69af6c6
--- /dev/null
+++ b/sim/transport/steer/CbmTransportConfig.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "CbmConfigBase.h"
+
+class CbmTransport;
+
+class CbmTransportConfig : public CbmConfigBase<CbmTransportConfig, CbmTransport> {
+
+public:
+  using TagSet_t = CbmConfigBase<CbmTransportConfig, CbmTransport>::TagSet_t;
+
+  static std::string GetModuleTag();
+  static TagSet_t GetValidationTags();
+  static TagSet_t GetAcceptedGenerators();
+  static bool LoadImpl(CbmTransport& obj, const pt::ptree& moduleTree);
+  static bool SetIO(CbmTransport& obj, const pt::ptree& moduleTree);
+  static bool SetTarget(CbmTransport& obj, const pt::ptree& moduleTree);
+  static bool SetBeamProfile(CbmTransport& obj, const pt::ptree& moduleTree);
+  static bool SetTransportParameters(CbmTransport& obj, const pt::ptree& moduleTree);
+  static bool SetGeometry(CbmTransport& obj, const pt::ptree& moduleTree);
+
+  ClassDef(CbmTransportConfig, 1);
+};