diff --git a/include/config.h b/include/config.h
index 9243bf35..c47eb683 100644
--- a/include/config.h
+++ b/include/config.h
@@ -41,6 +41,9 @@ struct sway_config {
 	bool active;
 	bool failed;
 	bool reloading;
+
+	int gaps_inner;
+	int gaps_outer;
 };
 
 bool load_config(void);
diff --git a/include/container.h b/include/container.h
index 186ee8b6..6d64b490 100644
--- a/include/container.h
+++ b/include/container.h
@@ -48,6 +48,8 @@ struct sway_container {
 
 	char *name;
 
+	int gaps;
+
 	list_t *children;
 	list_t *floating;
 
diff --git a/sway/commands.c b/sway/commands.c
index 6c3efb3b..54839322 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -3,6 +3,7 @@
 #include <wlc/wlc.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
 #include <unistd.h>
 #include <ctype.h>
@@ -281,6 +282,44 @@ static bool cmd_focus_follows_mouse(struct sway_config *config, int argc, char *
 	return true;
 }
 
+static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
+	if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
+		return false;
+	}
+
+	if (argc == 1) {
+		char *end;
+		int amount = (int)strtol(argv[0], &end, 10);
+		if (errno == ERANGE || amount == 0) {
+			errno = 0;
+			return false;
+		}
+		if (config->gaps_inner == 0) {
+			config->gaps_inner = amount;
+		}
+		if (config->gaps_outer == 0) {
+			config->gaps_outer = amount;
+		}
+	} else if (argc == 2) {
+		char *end;
+		int amount = (int)strtol(argv[1], &end, 10);
+		if (errno == ERANGE || amount == 0) {
+			errno = 0;
+			return false;
+		}
+		if (strcmp(argv[0], "inner") == 0) {
+			config->gaps_inner = amount;
+		} else if (strcmp(argv[0], "outer") == 0) {
+			config->gaps_outer = amount;
+		} else {
+			return false;
+		}
+	} else {
+		return false;
+	}
+	return true;
+}
+
 static bool cmd_kill(struct sway_config *config, int argc, char **argv) {
 	swayc_t *view = get_focused_container(&root_container);
 	wlc_view_close(view->handle);
@@ -484,6 +523,7 @@ static struct cmd_handler handlers[] = {
 	{ "focus", cmd_focus },
 	{ "focus_follows_mouse", cmd_focus_follows_mouse },
 	{ "fullscreen", cmd_fullscreen },
+	{ "gaps", cmd_gaps },
 	{ "kill", cmd_kill },
 	{ "layout", cmd_layout },
 	{ "log_colors", cmd_log_colors },
diff --git a/sway/config.c b/sway/config.c
index d4871bab..637e2dbc 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -170,6 +170,8 @@ void config_defaults(struct sway_config *config) {
 	config->reloading = false;
 	config->active = false;
 	config->failed = false;
+	config->gaps_inner = 0;
+	config->gaps_outer = 0;
 }
 
 bool read_config(FILE *file, bool is_active) {
diff --git a/sway/container.c b/sway/container.c
index 62c5bda0..06111674 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -63,8 +63,10 @@ swayc_t *new_output(wlc_handle handle) {
 	sway_log(L_DEBUG, "Added output %lu:%s", handle, name);
 
 	swayc_t *output = new_swayc(C_OUTPUT);
-	output->width = size->w;
-	output->height = size->h;
+	output->x = (config->gaps_outer + config->gaps_inner) / 2;
+	output->y = (config->gaps_outer + config->gaps_inner) / 2;
+	output->width = size->w - (config->gaps_outer + config->gaps_inner);
+	output->height = size->h - (config->gaps_outer + config->gaps_inner);
 	output->handle = handle;
 	output->name = name ? strdup(name) : NULL;
 
@@ -105,6 +107,8 @@ swayc_t *new_workspace(swayc_t *output, const char *name) {
 	swayc_t *workspace = new_swayc(C_WORKSPACE);
 
 	workspace->layout = L_HORIZ; // TODO: default layout
+	workspace->x = output->x;
+	workspace->y = output->y;
 	workspace->width = output->width;
 	workspace->height = output->height;
 	workspace->name = strdup(name);
@@ -167,6 +171,8 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
 	view->visible = true;
 	view->is_focused = true;
 
+	view->gaps = config->gaps_inner;
+
 	view->desired_width = -1;
 	view->desired_height = -1;
 
diff --git a/sway/layout.c b/sway/layout.c
index a6a241f4..02c92026 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -135,12 +135,12 @@ void arrange_windows(swayc_t *container, int width, int height) {
 		{
 			struct wlc_geometry geometry = {
 				.origin = {
-					.x = container->x,
-					.y = container->y
+					.x = container->x + container->gaps / 2,
+					.y = container->y + container->gaps / 2
 				},
 				.size = {
-					.w = width,
-					.h = height
+					.w = width - container->gaps,
+					.h = height - container->gaps
 				}
 			};
 			if (wlc_view_get_state(container->handle) & WLC_BIT_FULLSCREEN) {
@@ -148,10 +148,10 @@ void arrange_windows(swayc_t *container, int width, int height) {
 				while (parent->type != C_OUTPUT) {
 					parent = parent->parent;
 				}
-				geometry.origin.x = 0;
-				geometry.origin.y = 0;
-				geometry.size.w = parent->width;
-				geometry.size.h = parent->height;
+				geometry.origin.x = container->gaps / 2;
+				geometry.origin.y = container->gaps / 2;
+				geometry.size.w = parent->width - container->gaps;
+				geometry.size.h = parent->height - container->gaps;
 				wlc_view_set_geometry(container->handle, 0, &geometry);
 				wlc_view_bring_to_front(container->handle);
 			} else {