diff --git a/dumux/python/CMakeLists.txt b/dumux/python/CMakeLists.txt
index 82890da7ca6d0dbbd20641257f8bb73a72ddefa4..ee2d01c4360e8acb483760aa7c794ab285beb0f9 100644
--- a/dumux/python/CMakeLists.txt
+++ b/dumux/python/CMakeLists.txt
@@ -1,3 +1,5 @@
 add_subdirectory(assembly)
 add_subdirectory(common)
 add_subdirectory(discretization)
+add_subdirectory(io)
+add_subdirectory(material)
diff --git a/dumux/python/material/CMakeLists.txt b/dumux/python/material/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f1c168afc35b03db804df7829820e885bd607308
--- /dev/null
+++ b/dumux/python/material/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory(components)
+add_subdirectory(fluidsystems)
+add_subdirectory(spatialparams)
diff --git a/dumux/python/material/components/CMakeLists.txt b/dumux/python/material/components/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7aaff78f8d4d2739a3c718c0abc092f5ff5daf51
--- /dev/null
+++ b/dumux/python/material/components/CMakeLists.txt
@@ -0,0 +1,3 @@
+file(GLOB DUMUX_PYTHON_MATERIAL_COMPONENTS_HEADERS *.hh *.inc)
+install(FILES ${DUMUX_PYTHON_MATERIAL_COMPONENTS_HEADERS}
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/python/material/components)
diff --git a/dumux/python/material/components/component.hh b/dumux/python/material/components/component.hh
new file mode 100644
index 0000000000000000000000000000000000000000..288e867d1c7ab6d3488b4d4fdc35f5a9492234e0
--- /dev/null
+++ b/dumux/python/material/components/component.hh
@@ -0,0 +1,75 @@
+#ifndef DUMUX_PYTHON_MATERIAL_COMPONENT_HH
+#define DUMUX_PYTHON_MATERIAL_COMPONENT_HH
+
+#include <dune/python/pybind11/pybind11.h>
+#include <dune/python/pybind11/stl.h>
+
+#include <dumux/material/components/componenttraits.hh>
+
+
+namespace Dumux::Python {
+
+
+template <class Comp, class... options>
+void registerComponent(pybind11::handle scope,
+                       pybind11::class_<Comp, options...> cls)
+{
+    using pybind11::operator""_a;
+
+    cls.def(pybind11::init());
+
+    cls.def_static("name", &Comp::name);
+    cls.def_static("molarMass", &Comp::molarMass);
+
+    if constexpr (ComponentTraits<Comp>::hasLiquidState)
+    {
+        cls.def_static("liquidDensity", &Comp::liquidDensity, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidMolarDensity", &Comp::liquidMolarDensity, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidIsCompressible", &Comp::liquidIsCompressible);
+        cls.def_static("liquidViscosity", &Comp::liquidViscosity, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidEnthalpy", &Comp::liquidEnthalpy, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidInternalEnergy", &Comp::liquidInternalEnergy, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidHeatCapacity", &Comp::liquidHeatCapacity, "temperature"_a, "pressure"_a);
+        cls.def_static("liquidThermalConductivity", &Comp::liquidThermalConductivity, "temperature"_a, "pressure"_a);
+        cls.def_static("vaporPressure", &Comp::vaporPressure, "temperature"_a);
+    }
+
+    if constexpr (ComponentTraits<Comp>::hasGasState)
+    {
+        using Scalar = typename Comp::Scalar;
+        cls.def_static("gasDensity", &Comp::gasDensity, "temperature"_a, "pressure"_a);
+        cls.def_static("gasMolarDensity", &Comp::gasMolarDensity, "temperature"_a, "pressure"_a);
+        cls.def_static("gasIsCompressible", &Comp::gasIsCompressible);
+        cls.def_static("gasIsIdeal", &Comp::gasIsIdeal);
+        cls.def_static("gasPressure", &Comp::gasPressure, "temperature"_a, "pressure"_a);
+        cls.def_static("gasViscosity", &Comp::gasViscosity, "temperature"_a, "pressure"_a);
+        cls.def_static("gasEnthalpy", &Comp::gasEnthalpy, "temperature"_a, "pressure"_a);
+        cls.def_static("gasInternalEnergy", &Comp::gasInternalEnergy, "temperature"_a, "pressure"_a);
+        cls.def_static("gasHeatCapacity", &Comp::gasHeatCapacity, "temperature"_a, "pressure"_a);
+        cls.def_static("gasThermalConductivity", &Comp::gasThermalConductivity, "temperature"_a, "pressure"_a);
+    }
+
+    if constexpr (ComponentTraits<Comp>::hasSolidState)
+    {
+        cls.def_static("solidIsCompressible", &Comp::solidIsCompressible);
+        cls.def_static("solidDensity", &Comp::solidDensity, "temperature_a");
+        cls.def_static("solidThermalConductivity", &Comp::solidThermalConductivity, "temperature_a");
+        cls.def_static("solidHeatCapacity", &Comp::solidHeatCapacity, "temperature_a");
+    }
+
+    if constexpr (ComponentTraits<Comp>::isIon)
+    {
+        cls.def_static("charge", &Comp::charge);
+    }
+
+    if constexpr (ComponentTraits<Comp>::hasLiquidState || ComponentTraits<Comp>::hasGasState)
+    {
+        cls.def_static("criticalTemperature", &Comp::criticalTemperature);
+        cls.def_static("criticalPressure", &Comp::criticalPressure);
+    }
+}
+
+
+} // namespace Dumux::Python
+
+#endif
diff --git a/dumux/python/material/fluidsystems/CMakeLists.txt b/dumux/python/material/fluidsystems/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..91ab2273ca4e04474252d75a848cf29211f1c414
--- /dev/null
+++ b/dumux/python/material/fluidsystems/CMakeLists.txt
@@ -0,0 +1,3 @@
+file(GLOB DUMUX_PYTHON_MATERIAL_FLUIDSYSTEMS_HEADERS *.hh *.inc)
+install(FILES ${DUMUX_PYTHON_MATERIAL_FLUIDSYSTEMS_HEADERS}
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/python/material/fluidsystems)
diff --git a/dumux/python/material/fluidsystems/fluidsystem.hh b/dumux/python/material/fluidsystems/fluidsystem.hh
new file mode 100644
index 0000000000000000000000000000000000000000..7cf246b9151470900b072b9562221f78cc6ffb80
--- /dev/null
+++ b/dumux/python/material/fluidsystems/fluidsystem.hh
@@ -0,0 +1,41 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 3 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief TODO: docme!
+ */
+
+#ifndef DUMUX_PYTHON_MATERIAL_FLUIDSYSTEMS_FLUIDSYSTEM_HH
+#define DUMUX_PYTHON_MATERIAL_FLUIDSYSTEMS_FLUIDSYSTEM_HH
+
+#include <dune/python/pybind11/pybind11.h>
+#include <dune/python/pybind11/stl.h>
+
+namespace Dumux::Python {
+
+template <class FS, class... options>
+void registerFluidSystem(pybind11::handle scope,
+                         pybind11::class_<FS, options...> cls)
+{
+    cls.def(pybind11::init());
+}
+
+} // namespace Dumux::Python
+
+#endif
diff --git a/dumux/python/material/spatialparams/CMakeLists.txt b/dumux/python/material/spatialparams/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..08816c5b1a287597d371c037e0e4703c0496b7cf
--- /dev/null
+++ b/dumux/python/material/spatialparams/CMakeLists.txt
@@ -0,0 +1,3 @@
+file(GLOB DUMUX_PYTHON_MATERIAL_SPATIALPARAMS_HEADERS *.hh *.inc)
+install(FILES ${DUMUX_PYTHON_MATERIAL_SPATIALPARAMS_HEADERS}
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/python/material/spatialparams)
diff --git a/dumux/python/material/spatialparams/spatialparams.hh b/dumux/python/material/spatialparams/spatialparams.hh
new file mode 100644
index 0000000000000000000000000000000000000000..e072d9bdd928b9c1e72136e832da4cae2a1d44d4
--- /dev/null
+++ b/dumux/python/material/spatialparams/spatialparams.hh
@@ -0,0 +1,47 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 3 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief TODO: docme!
+ */
+
+#ifndef DUMUX_PYTHON_MATERIAL_SPATIAL_PARAMS_HH
+#define DUMUX_PYTHON_MATERIAL_SPATIAL_PARAMS_HH
+
+
+#include <dune/python/pybind11/pybind11.h>
+#include <dune/python/pybind11/stl.h>
+
+namespace Dumux::Python {
+
+template <class SP, class... options>
+void registerSpatialParams(pybind11::handle scope,
+                           pybind11::class_<SP, options...> cls)
+{
+    using pybind11::operator""_a;
+    using GridGeometry = std::decay_t<decltype(std::declval<SP>().gridGeometry())>;
+
+    cls.def(pybind11::init([](std::shared_ptr<GridGeometry> gridGeometry){
+        return std::make_shared<SP>(gridGeometry);
+    }), "gridGeometry"_a);
+}
+
+} // namespace Dumux::Python
+
+#endif
diff --git a/python/dumux/CMakeLists.txt b/python/dumux/CMakeLists.txt
index 55e55714992a5e32ab80a1af2866b6683bed793c..5e7c41d12f002722b512111d7d22b1cfc30c6b32 100644
--- a/python/dumux/CMakeLists.txt
+++ b/python/dumux/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(assembly)
 add_subdirectory(common)
 add_subdirectory(discretization)
+add_subdirectory(material)
 
 add_python_targets(dumux
   __init__
diff --git a/python/dumux/material/CMakeLists.txt b/python/dumux/material/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c6683fdb0b9fc87f479c79f405fa95c1e2703360
--- /dev/null
+++ b/python/dumux/material/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_subdirectory(components)
+add_subdirectory(fluidsystems)
+add_subdirectory(spatialparams)
+
+add_python_targets(material
+  __init__
+)
diff --git a/python/dumux/material/__init__.py b/python/dumux/material/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd20d3b3700effd3a40512aa63d34c7534b82248
--- /dev/null
+++ b/python/dumux/material/__init__.py
@@ -0,0 +1,3 @@
+from dumux.material.fluidsystems import FluidSystem
+from dumux.material.components import Component
+from dumux.material.spatialparams import SpatialParams
diff --git a/python/dumux/material/components/CMakeLists.txt b/python/dumux/material/components/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e02d4be73abc3753a51c9aadb95d408b2578d270
--- /dev/null
+++ b/python/dumux/material/components/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_python_targets(components
+  __init__
+)
diff --git a/python/dumux/material/components/__init__.py b/python/dumux/material/components/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ce504e897699f46ae5736119a5549857f771b6e
--- /dev/null
+++ b/python/dumux/material/components/__init__.py
@@ -0,0 +1,25 @@
+from dune.generator.generator import SimpleGenerator
+
+
+components = {
+    "Air": "dumux/material/components/air.hh",
+    "H2O": "dumux/material/components/h2o.hh",
+    "SimpleH2O": "dumux/material/components/simpleh2o.hh",
+    "N2": "dumux/material/components/n2.hh",
+    "Calcite": "dumux/material/components/calcite.hh",
+}
+
+
+def Component(*, name, scalar="double"):
+    moduleName = name
+    typeName = f"Dumux::Components::{name} <{scalar}>"
+    includes = ["dumux/python/material/components/component.hh"]
+    includes += [components[name]]
+    generator = SimpleGenerator("Component", "Dumux::Python")
+    module = generator.load(includes, typeName, moduleName)
+    return module.Component()
+
+
+def listComponents():
+    print("The following components are availabe:")
+    print(components.keys())
diff --git a/python/dumux/material/fluidsystems/CMakeLists.txt b/python/dumux/material/fluidsystems/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..172368eadc24dffd751aff799c0b44341e5cc590
--- /dev/null
+++ b/python/dumux/material/fluidsystems/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_python_targets(fluidsystems
+  __init__
+)
diff --git a/python/dumux/material/fluidsystems/__init__.py b/python/dumux/material/fluidsystems/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5174e9093ce70742430746e159f5551cdd07909c
--- /dev/null
+++ b/python/dumux/material/fluidsystems/__init__.py
@@ -0,0 +1,31 @@
+from dune.generator.generator import SimpleGenerator
+from dune.common.hashit import hashIt
+
+# construct a FluidSystem
+# the FluidSystem is JIT compiled
+def FluidSystem(*, type, component, scalar="double"):
+    includes = component._includes + ["dumux/python/material/fluidsystems/fluidsystem.hh"]
+
+    availableFluidSystems = {
+        "OnePLiquid": {
+            "includes": ["dumux/material/fluidsystems/1pliquid.hh"],
+            "type": f"Dumux::FluidSystems::OnePLiquid<{scalar._typeName}, {component._typeName}>",
+        },
+        "OnePGas": {
+            "includes": ["dumux/material/fluidsystems/1pgas.hh"],
+            "type": f"Dumux::FluidSystems::OnePGas<{scalar._typeName}, {component._typeName}>",
+        },
+    }
+    if type not in availableFluidSystems:
+        raise NotImplementedError(
+            "FluidSystem of type " + type + " not implemented.\n"
+            "Available types are " + ", ".join(availableFluidSystems.keys())
+        )
+
+    includes += availableFluidSystems[type]["includes"]
+    typeName = availableFluidSystems[type]["type"]
+
+    moduleName = "FluidSystem_" + hashIt(typeName)
+    generator = SimpleGenerator("FluidSystem", "Dumux::Python")
+    module = generator.load(includes, typeName, moduleName)
+    return module.FluidSystem()
diff --git a/python/dumux/material/spatialparams/CMakeLists.txt b/python/dumux/material/spatialparams/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..db81731a161e443a1c2c0f686cbf84d16af1d2cb
--- /dev/null
+++ b/python/dumux/material/spatialparams/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_python_targets(spatialparams
+  __init__
+)
diff --git a/python/dumux/material/spatialparams/__init__.py b/python/dumux/material/spatialparams/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..63472d5ca9f0cf4d5d2db113fb1cf3b4142eccf3
--- /dev/null
+++ b/python/dumux/material/spatialparams/__init__.py
@@ -0,0 +1,14 @@
+from dune.generator.generator import SimpleGenerator
+
+def SpatialParams(gridGeometry, scalar):
+    moduleName = 'spatialparams'
+    typeName = "Dumux::FVSpatialParamsOnePConstant<{}, {}>".format(gridGeometry._typeName, scalar._typeName)
+    includes = ["dumux/material/spatialparams/fv1pconstant.hh"]
+    includes += ["dumux/python/material/spatialparams/spatialparams.hh"]
+    includes += gridGeometry._includes
+    holderType = "std::shared_ptr<{}>".format(typeName)
+
+    generator = SimpleGenerator("SpatialParams", "Dumux::Python")
+    module = generator.load(includes, typeName, moduleName, options=[holderType])
+
+    return module.SpatialParams(gridGeometry)