diff --git a/include/sway/commands.h b/include/sway/commands.h
index 593ae0f1..7ca0bda8 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -216,6 +216,15 @@ sway_cmd input_cmd_xkb_options;
 sway_cmd input_cmd_xkb_rules;
 sway_cmd input_cmd_xkb_variant;
 
+sway_cmd output_cmd_background;
+sway_cmd output_cmd_disable;
+sway_cmd output_cmd_dpms;
+sway_cmd output_cmd_enable;
+sway_cmd output_cmd_mode;
+sway_cmd output_cmd_position;
+sway_cmd output_cmd_scale;
+sway_cmd output_cmd_transform;
+
 sway_cmd seat_cmd_attach;
 sway_cmd seat_cmd_fallback;
 sway_cmd seat_cmd_cursor;
diff --git a/include/sway/config.h b/include/sway/config.h
index b597da75..81e9c382 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -372,10 +372,15 @@ struct sway_config {
 	// Context for command handlers
 	struct {
 		struct input_config *input_config;
+		struct output_config *output_config;
 		struct seat_config *seat_config;
 		struct sway_seat *seat;
 		struct sway_container *current_container;
 		bool using_criteria;
+		struct {
+			int argc;
+			char **argv;
+		} leftovers;
 	} handler_context;
 };
 
diff --git a/sway/commands/output.c b/sway/commands/output.c
index e8881f77..a7d325ec 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -1,254 +1,24 @@
-#define _XOPEN_SOURCE 500
-#include <ctype.h>
-#include <libgen.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <wordexp.h>
 #include "sway/commands.h"
 #include "sway/config.h"
 #include "list.h"
 #include "log.h"
-#include "stringop.h"
 
-static char *bg_options[] = {
-	"stretch",
-	"center",
-	"fill",
-	"fit",
-	"tile",
+// must be in order for the bsearch
+static struct cmd_handler output_handlers[] = {
+	{ "background", output_cmd_background },
+	{ "bg", output_cmd_background },
+	{ "disable", output_cmd_disable },
+	{ "dpms", output_cmd_dpms },
+	{ "enable", output_cmd_enable },
+	{ "mode", output_cmd_mode },
+	{ "pos", output_cmd_position },
+	{ "position", output_cmd_position },
+	{ "res", output_cmd_mode },
+	{ "resolution", output_cmd_mode },
+	{ "scale", output_cmd_scale },
+	{ "transform", output_cmd_transform },
 };
 
-static struct cmd_results *cmd_output_dpms(struct output_config *output,
-		int *i, int argc, char **argv) {
-
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
-	}
-
-	char *value = argv[*i];
-	if (strcmp(value, "on") == 0) {
-		output->dpms_state = DPMS_ON;
-	} else if (strcmp(value, "off") == 0) {
-		output->dpms_state = DPMS_OFF;
-	} else {
-		return cmd_results_new(CMD_INVALID, "output",
-				"Invalid dpms state, valid states are on/off.");
-	}
-	return NULL;
-}
-
-static struct cmd_results *cmd_output_mode(struct output_config *output,
-		int *i, int argc, char **argv) {
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output", "Missing mode argument.");
-	}
-
-	char *end;
-	output->width = strtol(argv[*i], &end, 10);
-	if (*end) {
-		// Format is 1234x4321
-		if (*end != 'x') {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid mode width.");
-		}
-		++end;
-		output->height = strtol(end, &end, 10);
-		if (*end) {
-			if (*end != '@') {
-				return cmd_results_new(CMD_INVALID, "output",
-					"Invalid mode height.");
-			}
-			++end;
-			output->refresh_rate = strtof(end, &end);
-			if (strcasecmp("Hz", end) != 0) {
-				return cmd_results_new(CMD_INVALID, "output",
-					"Invalid mode refresh rate.");
-			}
-		}
-	} else {
-		// Format is 1234 4321
-		if (++*i >= argc) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Missing mode argument (height).");
-		}
-		output->height = strtol(argv[*i], &end, 10);
-		if (*end) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid mode height.");
-		}
-	}
-
-	return NULL;
-}
-
-static struct cmd_results *cmd_output_position(struct output_config *output,
-		int *i, int argc, char **argv) {
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Missing position argument.");
-	}
-
-	char *end;
-	output->x = strtol(argv[*i], &end, 10);
-	if (*end) {
-		// Format is 1234,4321
-		if (*end != ',') {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid position x.");
-		}
-		++end;
-		output->y = strtol(end, &end, 10);
-		if (*end) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid position y.");
-		}
-	} else {
-		// Format is 1234 4321 (legacy)
-		if (++*i >= argc) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Missing position argument (y).");
-		}
-		output->y = strtol(argv[*i], &end, 10);
-		if (*end) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid position y.");
-		}
-	}
-
-	return NULL;
-}
-
-static struct cmd_results *cmd_output_scale(struct output_config *output,
-		int *i, int argc, char **argv) {
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Missing scale argument.");
-	}
-
-	char *end;
-	output->scale = strtof(argv[*i], &end);
-	if (*end) {
-		return cmd_results_new(CMD_INVALID, "output", "Invalid scale.");
-	}
-
-	return NULL;
-}
-
-static struct cmd_results *cmd_output_transform(struct output_config *output,
-		int *i, int argc, char **argv) {
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Missing transform argument.");
-	}
-
-	char *value = argv[*i];
-	if (strcmp(value, "normal") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
-	} else if (strcmp(value, "90") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_90;
-	} else if (strcmp(value, "180") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_180;
-	} else if (strcmp(value, "270") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_270;
-	} else if (strcmp(value, "flipped") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
-	} else if (strcmp(value, "flipped-90") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
-	} else if (strcmp(value, "flipped-180") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
-	} else if (strcmp(value, "flipped-270") == 0) {
-		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
-	} else {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Invalid output transform.");
-	}
-
-	return NULL;
-}
-
-static struct cmd_results *cmd_output_background(struct output_config *output,
-		int *i, int argc, char **argv) {
-	if (++*i >= argc) {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Missing background file or color specification.");
-	}
-	const char *background = argv[*i];
-	if (*i + 1 >= argc) {
-		return cmd_results_new(CMD_INVALID, "output",
-			"Missing background scaling mode or `solid_color`.");
-	}
-	const char *background_option = argv[*i];
-
-	if (strcasecmp(background_option, "solid_color") == 0) {
-		output->background = strdup(background);
-		output->background_option = strdup("solid_color");
-	} else {
-		bool valid = false;
-		char *mode;
-		size_t j;
-		for (j = 0; j < (size_t)(argc - *i); ++j) {
-			mode = argv[*i + j];
-			size_t n = sizeof(bg_options) / sizeof(char *);
-			for (size_t k = 0; k < n; ++k) {
-				if (strcasecmp(mode, bg_options[k]) == 0) {
-					valid = true;
-					break;
-				}
-			}
-			if (valid) {
-				break;
-			}
-		}
-		if (!valid) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Missing background scaling mode.");
-		}
-
-		wordexp_t p;
-		char *src = join_args(argv + *i, j);
-		if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
-			return cmd_results_new(CMD_INVALID, "output",
-				"Invalid syntax (%s).", src);
-		}
-		free(src);
-		src = p.we_wordv[0];
-		if (config->reading && *src != '/') {
-			char *conf = strdup(config->current_config);
-			if (conf) {
-				char *conf_path = dirname(conf);
-				src = malloc(strlen(conf_path) + strlen(src) + 2);
-				if (src) {
-					sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
-				} else {
-					wlr_log(L_ERROR,
-						"Unable to allocate background source");
-				}
-				free(conf);
-			} else {
-				wlr_log(L_ERROR, "Unable to allocate background source");
-			}
-		}
-		if (!src || access(src, F_OK) == -1) {
-			wordfree(&p);
-			return cmd_results_new(CMD_INVALID, "output",
-				"Background file unreadable (%s).", src);
-		}
-
-		output->background = strdup(src);
-		output->background_option = strdup(mode);
-		if (src != p.we_wordv[0]) {
-			free(src);
-		}
-		wordfree(&p);
-
-		*i += j;
-	}
-
-	return NULL;
-}
-
 struct cmd_results *cmd_output(int argc, char **argv) {
 	struct cmd_results *error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1);
 	if (error != NULL) {
@@ -260,40 +30,31 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 		wlr_log(L_ERROR, "Failed to allocate output config");
 		return NULL;
 	}
+	argc--; argv++;
 
-	for (int i = 1; i < argc; ++i) {
-		const char *command = argv[i];
+	config->handler_context.output_config = output;
 
-		if (strcasecmp(command, "enable") == 0) {
-			output->enabled = 1;
-		} else if (strcasecmp(command, "disable") == 0) {
-			output->enabled = 0;
-		} else if (strcasecmp(command, "mode") == 0 ||
-				strcasecmp(command, "resolution") == 0 ||
-				strcasecmp(command, "res") == 0) {
-			error = cmd_output_mode(output, &i, argc, argv);
-		} else if (strcasecmp(command, "position") == 0 ||
-				strcasecmp(command, "pos") == 0) {
-			error = cmd_output_position(output, &i, argc, argv);
-		} else if (strcasecmp(command, "scale") == 0) {
-			error = cmd_output_scale(output, &i, argc, argv);
-		} else if (strcasecmp(command, "transform") == 0) {
-			error = cmd_output_transform(output, &i, argc, argv);
-		} else if (strcasecmp(command, "background") == 0 ||
-				strcasecmp(command, "bg") == 0) {
-			error = cmd_output_background(output, &i, argc, argv);
-		} else if (strcasecmp(command, "dpms") == 0) {
-			error = cmd_output_dpms(output, &i, argc, argv);
+	while (argc > 0) {
+		if (find_handler(*argv, output_handlers, sizeof(output_handlers))) {
+			error = config_subcommand(argv, argc, output_handlers,
+					sizeof(output_handlers));
 		} else {
 			error = cmd_results_new(CMD_INVALID, "output",
-				"Invalid output subcommand: %s.", command);
+				"Invalid output subcommand: %s.", *argv);
 		}
 
 		if (error != NULL) {
 			goto fail;
 		}
+
+		argc = config->handler_context.leftovers.argc;
+		argv = config->handler_context.leftovers.argv;
 	}
 
+	config->handler_context.output_config = NULL;
+	config->handler_context.leftovers.argc = 0;
+	config->handler_context.leftovers.argv = NULL;
+
 	int i = list_seq_find(config->output_configs, output_name_cmp, output->name);
 	if (i >= 0) {
 		// Merge existing config
@@ -338,6 +99,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 
 fail:
+	config->handler_context.output_config = NULL;
 	free_output_config(output);
 	return error;
 }
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
new file mode 100644
index 00000000..f039c9c9
--- /dev/null
+++ b/sway/commands/output/background.c
@@ -0,0 +1,105 @@
+#define _XOPEN_SOURCE 500
+#include <libgen.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
+#include "stringop.h"
+
+static char *bg_options[] = {
+	"stretch",
+	"center",
+	"fill",
+	"fit",
+	"tile",
+};
+
+struct cmd_results *output_cmd_background(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Missing background file or color specification.");
+	}
+	if (argc < 2) {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Missing background scaling mode or `solid_color`.");
+	}
+
+	struct output_config *output = config->handler_context.output_config;
+
+	if (strcasecmp(argv[1], "solid_color") == 0) {
+		output->background = calloc(1, strlen(argv[0]) + 3);
+		snprintf(output->background, strlen(argv[0]) + 3, "\"%s\"", argv[0]);
+		output->background_option = strdup("solid_color");
+		argc -= 2; argv += 2;
+	} else {
+		bool valid = false;
+		char *mode;
+		size_t j;
+		for (j = 0; j < (size_t)argc; ++j) {
+			mode = argv[j];
+			size_t n = sizeof(bg_options) / sizeof(char *);
+			for (size_t k = 0; k < n; ++k) {
+				if (strcasecmp(mode, bg_options[k]) == 0) {
+					valid = true;
+					break;
+				}
+			}
+			if (valid) {
+				break;
+			}
+		}
+		if (!valid) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Missing background scaling mode.");
+		}
+
+		wordexp_t p;
+		char *src = join_args(argv, j);
+		if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid syntax (%s).", src);
+		}
+		free(src);
+		src = p.we_wordv[0];
+		if (config->reading && *src != '/') {
+			char *conf = strdup(config->current_config);
+			if (conf) {
+				char *conf_path = dirname(conf);
+				src = malloc(strlen(conf_path) + strlen(src) + 2);
+				if (src) {
+					sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
+				} else {
+					wlr_log(L_ERROR,
+						"Unable to allocate background source");
+				}
+				free(conf);
+			} else {
+				wlr_log(L_ERROR, "Unable to allocate background source");
+			}
+		}
+		if (!src || access(src, F_OK) == -1) {
+			wordfree(&p);
+			return cmd_results_new(CMD_INVALID, "output",
+				"Background file unreadable (%s).", src);
+		}
+
+		output->background = strdup(src);
+		output->background_option = strdup(mode);
+		if (src != p.we_wordv[0]) {
+			free(src);
+		}
+		wordfree(&p);
+
+		argc -= j + 1; argv += j + 1;
+	}
+
+	config->handler_context.leftovers.argc = argc;
+	config->handler_context.leftovers.argv = argv;
+	return NULL;
+}
+
diff --git a/sway/commands/output/disable.c b/sway/commands/output/disable.c
new file mode 100644
index 00000000..65517c49
--- /dev/null
+++ b/sway/commands/output/disable.c
@@ -0,0 +1,13 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_disable(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	config->handler_context.output_config->enabled = 0;
+
+	config->handler_context.leftovers.argc = argc;
+	config->handler_context.leftovers.argv = argv;
+	return NULL;
+}
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c
new file mode 100644
index 00000000..0959ea6b
--- /dev/null
+++ b/sway/commands/output/dpms.c
@@ -0,0 +1,24 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_dpms(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
+	}
+
+	if (strcmp(*argv, "on") == 0) {
+		config->handler_context.output_config->dpms_state = DPMS_ON;
+	} else if (strcmp(*argv, "off") == 0) {
+		config->handler_context.output_config->dpms_state = DPMS_OFF;
+	} else {
+		return cmd_results_new(CMD_INVALID, "output",
+				"Invalid dpms state, valid states are on/off.");
+	}
+
+	config->handler_context.leftovers.argc = argc - 1;
+	config->handler_context.leftovers.argv = argv + 1;
+	return NULL;
+}
diff --git a/sway/commands/output/enable.c b/sway/commands/output/enable.c
new file mode 100644
index 00000000..8e3314f8
--- /dev/null
+++ b/sway/commands/output/enable.c
@@ -0,0 +1,14 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_enable(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	config->handler_context.output_config->enabled = 1;
+
+	config->handler_context.leftovers.argc = argc;
+	config->handler_context.leftovers.argv = argv;
+	return NULL;
+}
+
diff --git a/sway/commands/output/mode.c b/sway/commands/output/mode.c
new file mode 100644
index 00000000..daec6d44
--- /dev/null
+++ b/sway/commands/output/mode.c
@@ -0,0 +1,55 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_mode(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output", "Missing mode argument.");
+	}
+
+	struct output_config *output = config->handler_context.output_config;
+
+	char *end;
+	output->width = strtol(*argv, &end, 10);
+	if (*end) {
+		// Format is 1234x4321
+		if (*end != 'x') {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid mode width.");
+		}
+		++end;
+		output->height = strtol(end, &end, 10);
+		if (*end) {
+			if (*end != '@') {
+				return cmd_results_new(CMD_INVALID, "output",
+					"Invalid mode height.");
+			}
+			++end;
+			output->refresh_rate = strtof(end, &end);
+			if (strcasecmp("Hz", end) != 0) {
+				return cmd_results_new(CMD_INVALID, "output",
+					"Invalid mode refresh rate.");
+			}
+		}
+	} else {
+		// Format is 1234 4321
+		if (!argc) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Missing mode argument (height).");
+		}
+		argc--; argv++;
+		output->height = strtol(*argv, &end, 10);
+		if (*end) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid mode height.");
+		}
+	}
+
+	config->handler_context.leftovers.argc = argc - 1;
+	config->handler_context.leftovers.argv = argv + 1;
+	return NULL;
+}
+
diff --git a/sway/commands/output/position.c b/sway/commands/output/position.c
new file mode 100644
index 00000000..c2aeb281
--- /dev/null
+++ b/sway/commands/output/position.c
@@ -0,0 +1,46 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_position(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Missing position argument.");
+	}
+
+	char *end;
+	config->handler_context.output_config->x = strtol(*argv, &end, 10);
+	if (*end) {
+		// Format is 1234,4321
+		if (*end != ',') {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid position x.");
+		}
+		++end;
+		config->handler_context.output_config->y = strtol(end, &end, 10);
+		if (*end) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid position y.");
+		}
+	} else {
+		// Format is 1234 4321 (legacy)
+		if (!argc) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Missing position argument (y).");
+		}
+		argc--; argv++;
+		config->handler_context.output_config->y = strtol(*argv, &end, 10);
+		if (*end) {
+			return cmd_results_new(CMD_INVALID, "output",
+				"Invalid position y.");
+		}
+	}
+
+	config->handler_context.leftovers.argc = argc - 1;
+	config->handler_context.leftovers.argv = argv + 1;
+	return NULL;
+}
+
diff --git a/sway/commands/output/scale.c b/sway/commands/output/scale.c
new file mode 100644
index 00000000..0b4cc131
--- /dev/null
+++ b/sway/commands/output/scale.c
@@ -0,0 +1,23 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_scale(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Missing scale argument.");
+	}
+
+	char *end;
+	config->handler_context.output_config->scale = strtof(*argv, &end);
+	if (*end) {
+		return cmd_results_new(CMD_INVALID, "output", "Invalid scale.");
+	}
+
+	config->handler_context.leftovers.argc = argc - 1;
+	config->handler_context.leftovers.argv = argv + 1;
+	return NULL;
+}
diff --git a/sway/commands/output/transform.c b/sway/commands/output/transform.c
new file mode 100644
index 00000000..f9a94d64
--- /dev/null
+++ b/sway/commands/output/transform.c
@@ -0,0 +1,39 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_transform(int argc, char **argv) {
+	if (!config->handler_context.output_config) {
+		return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+	}
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Missing transform argument.");
+	}
+
+	struct output_config *output = config->handler_context.output_config;
+	if (strcmp(*argv, "normal") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	} else if (strcmp(*argv, "90") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_90;
+	} else if (strcmp(*argv, "180") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_180;
+	} else if (strcmp(*argv, "270") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_270;
+	} else if (strcmp(*argv, "flipped") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+	} else if (strcmp(*argv, "flipped-90") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
+	} else if (strcmp(*argv, "flipped-180") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+	} else if (strcmp(*argv, "flipped-270") == 0) {
+		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
+	} else {
+		return cmd_results_new(CMD_INVALID, "output",
+			"Invalid output transform.");
+	}
+
+	config->handler_context.leftovers.argc = argc - 1;
+	config->handler_context.leftovers.argv = argv + 1;
+	return NULL;
+}
diff --git a/sway/meson.build b/sway/meson.build
index 4c038583..b6bb02a7 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -120,6 +120,15 @@ sway_sources = files(
 	'commands/input/xkb_rules.c',
 	'commands/input/xkb_variant.c',
 
+	'commands/output/background.c',
+	'commands/output/disable.c',
+	'commands/output/dpms.c',
+	'commands/output/enable.c',
+	'commands/output/mode.c',
+	'commands/output/position.c',
+	'commands/output/scale.c',
+	'commands/output/transform.c',
+
 	'tree/arrange.c',
 	'tree/container.c',
 	'tree/layout.c',