diff --git a/README b/README
index 496f7b5303e0aaf672368c661c5eec81a17be037..52d0a5ca359c320a6568bb20da3b4e984b80cdd0 100644
--- a/README
+++ b/README
@@ -12,3 +12,11 @@ cd build
 cmake .. -DWALBERLA_DIR=path/to/walberla/sources
 
 
+How to build with code generation via pystencils / lbmpy
+=========================================================
+
+mkdir build
+cd build
+cmake .. -DWALBERLA_DIR=path/to/walberla/sources
+         -DWALBERLA_BUILD_WITH_CODEGEN=ON
+         -DPython_ROOT_DIR=path/to/python/root/directory
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 72226c4896f241d8a4489761f42ddaccb0c9862f..dc67defd81379dec8f5972eec238f08f1fce58fc 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -1 +1,5 @@
 add_subdirectory( example_app )
+
+if( WALBERLA_BUILD_WITH_CODEGEN )
+    add_subdirectory( example_app_codegen )
+endif()
\ No newline at end of file
diff --git a/apps/example_app_codegen/CMakeLists.txt b/apps/example_app_codegen/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3ba77d89073b58032a25d1f961a051971a4ac9af
--- /dev/null
+++ b/apps/example_app_codegen/CMakeLists.txt
@@ -0,0 +1,12 @@
+waLBerla_link_files_to_builddir( *.prm  *.py)
+
+waLBerla_generate_target_from_python(NAME LatticeModelGenerated FILE LatticeModel.py
+        OUT_FILES LatticeModel.cpp LatticeModel.h
+)
+
+
+waLBerla_add_executable ( NAME ExampleAppCodegen
+                          FILES ExampleApp.cpp
+                          DEPENDS blockforest core field lbm geometry timeloop gui
+                                  LatticeModelGenerated)
+
diff --git a/apps/example_app_codegen/ExampleApp.cpp b/apps/example_app_codegen/ExampleApp.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3cdda97703b2e9bf0e5ac3e7d0e09cab73168429
--- /dev/null
+++ b/apps/example_app_codegen/ExampleApp.cpp
@@ -0,0 +1,61 @@
+//======================================================================================================================
+//
+//  This file is part of waLBerla. waLBerla 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.
+//  
+//  waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
+//
+//! \file 01_BlocksAndFields.cpp
+//! \author Martin Bauer <martin.bauer@fau.de>
+//
+//======================================================================================================================
+
+#include "blockforest/Initialization.h"
+#include "core/Environment.h"
+#include "field/Field.h"
+#include "gui/Gui.h"
+#include "timeloop/SweepTimeloop.h"
+
+namespace walberla {
+
+Field<real_t, 1>* createFields(IBlock* const block, StructuredBlockStorage * const storage) {
+   return new Field<real_t,1>(storage->getNumberOfXCells(*block),
+                              storage->getNumberOfYCells(*block),
+                              storage->getNumberOfZCells(*block),
+                              real_c(0));
+}
+
+int main( int argc, char ** argv )
+{
+   walberla::Environment env( argc, argv );
+   
+   shared_ptr<StructuredBlockForest> blocks = blockforest::createUniformBlockGrid(
+                                                                                  uint_c(3), uint_c(2), uint_c(4),
+                                                                                  uint_c(10), uint_c(8), uint_c(12),
+                                                                                  real_c(0.5),
+                                                                                  false,
+                                                                                  false, false, false);
+   
+   blocks->addStructuredBlockData< Field<real_t,1> >( &createFields, "My Field" );
+
+   
+   SweepTimeloop timeloop( blocks, uint_c(1) );
+   GUI gui( timeloop, blocks, argc, argv );
+   gui.run();
+
+   return EXIT_SUCCESS;
+}
+}
+
+int main( int argc, char ** argv )
+{
+   return walberla::main(argc, argv);
+}
diff --git a/apps/example_app_codegen/LatticeModel.py b/apps/example_app_codegen/LatticeModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..446f2f02bfc4783d7d41a32059ca82f0f8716639
--- /dev/null
+++ b/apps/example_app_codegen/LatticeModel.py
@@ -0,0 +1,34 @@
+import sympy as sp
+
+from lbmpy import LBMConfig, LBMOptimisation, LBStencil, Method, Stencil
+from lbmpy.creationfunctions import create_lb_collision_rule, create_lb_update_rule
+
+from pystencils_walberla import CodeGeneration, generate_pack_info_from_kernel
+from lbmpy_walberla import generate_lattice_model
+
+#   ========================
+#      General Parameters
+#   ========================
+
+stencil = LBStencil(Stencil.D2Q9)
+omega = sp.Symbol('omega')
+layout = 'fzyx'
+
+#   Optimizations for the LBM Method
+lbm_opt = LBMOptimisation(cse_global=True, field_layout=layout)
+
+#   ===========================
+#      SRT Method Definition
+#   ===========================
+
+lbm_config = LBMConfig(stencil=stencil, method=Method.SRT, relaxation_rate=omega)
+
+collision_rule = create_lb_collision_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
+
+#   =====================
+#      Code Generation
+#   =====================
+
+with CodeGeneration() as ctx:
+    # generation of the lattice model ...
+    generate_lattice_model(ctx, "LatticeModel", collision_rule, field_layout=layout)