diff --git a/.gitignore b/.gitignore
index 74aeebbddd4b9dec384500f4ea6c65a54352f24e..c5f6b8d4b61e9db1bdd4edee810e5c5c1e108bdb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,8 @@ doc/doxygen/*.db
 doc/doxygen/*.tmp
 # Built binaries
 *bin
+# Build directory
+/build
 # Backup files
 *~
 *.orig
diff --git a/Makefile.include b/Makefile.include
index da23a2397e38b36f56810ce5e64025409accdf3f..2af5dbed2327324b296f2932eb70b53050cc1eec 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -23,6 +23,7 @@ RIOTTOOLS      ?= $(RIOTBASE)/dist/tools
 RIOTPROJECT    ?= $(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
 GITCACHE       ?= $(RIOTTOOLS)/git/git-cache
 GIT_CACHE_DIR  ?= $(HOME)/.gitcache
+BUILD_DIR      ?= $(RIOTBASE)/build
 APPDIR         ?= $(CURDIR)
 BINDIRBASE     ?= $(APPDIR)/bin
 BINDIR         ?= $(BINDIRBASE)/$(BOARD)
@@ -39,6 +40,7 @@ __DIRECTORY_VARIABLES := \
   RIOTTOOLS \
   RIOTPROJECT \
   APPDIR \
+  BUILD_DIR \
   BINDIRBASE \
   BINDIR \
   CCACHE_BASEDIR \
@@ -58,6 +60,7 @@ override RIOTTOOLS      := $(abspath $(RIOTTOOLS))
 override RIOTPROJECT    := $(abspath $(RIOTPROJECT))
 override GITCACHE       := $(abspath $(GITCACHE))
 override APPDIR         := $(abspath $(APPDIR))
+override BUILD_DIR      := $(abspath $(BUILD_DIR))
 override BINDIRBASE     := $(abspath $(BINDIRBASE))
 override BINDIR         := $(abspath $(BINDIR))
 override PKGDIRBASE     := $(abspath $(PKGDIRBASE))
diff --git a/makefiles/docker.inc.mk b/makefiles/docker.inc.mk
index 1f32a87cbf427f7a75fabc7e3135f847a37fcdda..775549f630540f9b4d08bddb4f471788c5a998bc 100644
--- a/makefiles/docker.inc.mk
+++ b/makefiles/docker.inc.mk
@@ -108,14 +108,18 @@ ETC_LOCALTIME = $(realpath /etc/localtime)
 # hardware which may not be reachable from inside the container.
 ..in-docker-container:
 	@$(COLOR_ECHO) '$(COLOR_GREEN)Launching build container using image "$(DOCKER_IMAGE)".$(COLOR_RESET)'
+	@# HACK: Handle directory creation here until it is provided globally
+	$(Q)mkdir -p $(BUILD_DIR)
 	$(DOCKER) run $(DOCKER_FLAGS) -t -u "$$(id -u)" \
 	    -v '$(RIOTBASE):$(DOCKER_BUILD_ROOT)/riotbase' \
+	    -v '$(BUILD_DIR):$(DOCKER_BUILD_ROOT)/build' \
 	    -v '$(RIOTCPU):$(DOCKER_BUILD_ROOT)/riotcpu' \
 	    -v '$(RIOTBOARD):$(DOCKER_BUILD_ROOT)/riotboard' \
 	    -v '$(RIOTMAKE):$(DOCKER_BUILD_ROOT)/riotmake' \
 	    -v '$(RIOTPROJECT):$(DOCKER_BUILD_ROOT)/riotproject' \
 	    -v '$(ETC_LOCALTIME):/etc/localtime:ro' \
 	    -e 'RIOTBASE=$(DOCKER_BUILD_ROOT)/riotbase' \
+	    -e 'BUILD_DIR=$(DOCKER_BUILD_ROOT)/build' \
 	    -e 'CCACHE_BASEDIR=$(DOCKER_BUILD_ROOT)/riotbase' \
 	    -e 'RIOTCPU=$(DOCKER_BUILD_ROOT)/riotcpu' \
 	    -e 'RIOTBOARD=$(DOCKER_BUILD_ROOT)/riotboard' \
diff --git a/makefiles/scan-build.inc.mk b/makefiles/scan-build.inc.mk
index 5160971c7e3ca9ad21d34114b6eafe29ca25ed0a..10fb376f0607f7edad225ccc6279a6c6d1dc218d 100644
--- a/makefiles/scan-build.inc.mk
+++ b/makefiles/scan-build.inc.mk
@@ -7,6 +7,7 @@ SCANBUILD_ENV_VARS := \
   BINDIR \
   BINDIRBASE \
   BOARD \
+  BUILD_DIR \
   BUILDRELPATH \
   CC \
   CFLAGS \
diff --git a/makefiles/vars.inc.mk b/makefiles/vars.inc.mk
index 0dee7327642c3beeeb7510f1d8d6b4436b970fca..cff66ea75bd84e9ba8ee17d94c3bd0aa20e30220 100644
--- a/makefiles/vars.inc.mk
+++ b/makefiles/vars.inc.mk
@@ -29,6 +29,7 @@ export RIOTPROJECT           # Top level git root of the project being built, or
 export RIOTMAKE              # Location of all supplemental Makefiles (such as this file)
 export BINDIRBASE            # This is the folder where the application should be built in. For each BOARD a different subfolder is used.
 export BINDIR                # This is the folder where the application should be built in.
+export BUILD_DIR             # This is the base folder to store common build files and artifacts, e.g. test results.
 export APPDIR                # The base folder containing the application
 export PKGDIRBASE            # The base folder for building packages