diff --git a/src/caoscrawler/crawl.py b/src/caoscrawler/crawl.py
index b0f576a2c73342cc1301ff0f27b74bb519768541..3a78392e56b55b152f10760b7bec9f9b205263af 100644
--- a/src/caoscrawler/crawl.py
+++ b/src/caoscrawler/crawl.py
@@ -49,12 +49,17 @@ from caosdb.apiutils import compare_entities, merge_entities
 from copy import deepcopy
 from jsonschema import validate
 
+from .macros import defmacro_constructor, macro_constructor
 
 import importlib
 
 SPECIAL_PROPERTIES_STRICT = ("description", "name", "id", "path")
 SPECIAL_PROPERTIES_NOT_STRICT = ("file", "checksum", "size")
 
+# Register the macro functions from the submodule:
+yaml.SafeLoader.add_constructor("!defmacro", defmacro_constructor)
+yaml.SafeLoader.add_constructor("!macro", macro_constructor)
+
 
 def check_identical(record1: db.Entity, record2: db.Entity, ignore_id=False):
     """
diff --git a/src/caoscrawler/macros/__init__.py b/src/caoscrawler/macros/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0acfb1763039a3bb800bbf0e26d6940b49d045cf
--- /dev/null
+++ b/src/caoscrawler/macros/__init__.py
@@ -0,0 +1 @@
+from .macro_yaml_object import defmacro_constructor, macro_constructor
diff --git a/src/caoscrawler/macros/macro_yaml_object.py b/src/caoscrawler/macros/macro_yaml_object.py
new file mode 100644
index 0000000000000000000000000000000000000000..2022f518fe1e3d627fbdcb87595898561f825348
--- /dev/null
+++ b/src/caoscrawler/macros/macro_yaml_object.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2022 Alexander Schlemmer
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+
+# Function to expand a macro in yaml
+# A. Schlemmer, 05/2022
+
+from dataclasses import dataclass
+from typing import Any
+from copy import deepcopy
+from string import Template
+
+@dataclass
+class MacroDefinition:
+    """
+    Stores a macro definition.
+    name: Name of the macro
+    params: variables and default values to be substituted in keys or values
+    definition: A dictionary that will be substituted including parameters
+    """
+    name: str
+    params: dict[str, Any]
+    definition: Any
+
+# This dictionary stores the macro definitions
+macro_store: dict[str, MacroDefinition] = dict()
+
+
+def substitute(propvalue, values: dict):
+    """
+    Substitution of variables in strings using the variable substitution
+    library from python's standard library.
+    """
+    propvalue_template = Template(propvalue)
+    return propvalue_template.safe_substitute(**values)
+
+
+def substitute_dict(sourced: dict[str, Any], values: dict[str, Any]):
+    """
+    Create a copy of sourced.
+    Afterwards recursively do variable substitution on all keys and values.
+    """
+    d = deepcopy(sourced)
+    # Changes in keys:
+    replace: dict[str, str] = dict()
+    for k in d:
+        replacement = substitute(k, values)
+        if replacement != k:
+            replace[k] = replacement
+    for k, v in replace.items():
+        d[v] = d[k]
+        del d[k]
+    # Changes in values:
+    for k, v in d.items():
+        if isinstance(v, str):
+            d[k] = substitute(v, values)
+        elif isinstance(v, list):
+            subst_list = list()
+            for i in d[k]:
+                if isinstance(i, str):
+                    subst_list.append(substitute(i, values))
+                else:
+                    subst_list.append(i)
+        elif isinstance(v, dict):
+            d[k] = substitute_dict(v, values)
+        else:
+            pass
+    return d
+
+
+def defmacro_constructor(loader, node):
+    """
+    Function for registering macros in yaml files.
+
+    It can be registered in pyaml using:
+    yaml.SafeLoader.add_constructor("!defmacro", defmacro_constructor)
+    """
+    value = loader.construct_mapping(node, deep=True)
+    macro = MacroDefinition(
+        value["name"], value["params"],
+        value["definition"])
+    macro_store[macro.name] = macro
+    return {}
+
+
+def macro_constructor(loader, node):
+    """
+    Function for substituting macros in yaml files.
+
+    It can be registered in pyaml using:
+    yaml.SafeLoader.add_constructor("!macro", macro_constructor)
+    """
+    value = loader.construct_mapping(node, deep=True)
+    name = value["name"]
+    macro = macro_store[name]
+    params = deepcopy(macro.params)
+    params.update(value["params"])
+    definition = deepcopy(macro.definition)
+    
+    return substitute_dict(definition, params)
diff --git a/unittests/test_macros.py b/unittests/test_macros.py
new file mode 100644
index 0000000000000000000000000000000000000000..2beced2f1f701535e70026e9cc760123ff965a0c
--- /dev/null
+++ b/unittests/test_macros.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2022 Alexander Schlemmer
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+
+from caoscrawler.macros import defmacro_constructor, macro_constructor
+import yaml
+
+def test_macros():
+    yaml.SafeLoader.add_constructor("!defmacro", defmacro_constructor)
+    yaml.SafeLoader.add_constructor("!macro", macro_constructor)
+    dat = yaml.load("""
+defs:
+- !defmacro
+  name: test
+  params:
+    a: 2
+    b: bla
+    c: $variable
+  definition:
+    expanded_$b:
+      blubb: ok$a
+      $b: $c
+
+testnode:
+  obl: !macro
+    name: test
+    params:
+      a: 4
+      b: yea
+""", Loader=yaml.SafeLoader)
+    assert dat["testnode"]["obl"]["expanded_yea"]["blubb"] == "ok4"
+    assert dat["testnode"]["obl"]["expanded_yea"]["yea"] == "$variable"
+    assert "expanded_bla" not in dat["testnode"]["obl"]
+    assert "bla" not in dat["testnode"]["obl"]["expanded_yea"]