diff --git a/include/sway/container.h b/include/sway/container.h
index 35d1c146..2a96165f 100644
--- a/include/sway/container.h
+++ b/include/sway/container.h
@@ -126,5 +126,6 @@ struct sway_container {
 };
 
 swayc_t *new_output(struct sway_output *sway_output);
+swayc_t *new_workspace(swayc_t *output, const char *name);
 
 #endif
diff --git a/include/sway/layout.h b/include/sway/layout.h
index 7e7a9c35..6356ad00 100644
--- a/include/sway/layout.h
+++ b/include/sway/layout.h
@@ -5,5 +5,7 @@ struct sway_container;
 
 void init_layout(void);
 void add_child(struct sway_container *parent, struct sway_container *child);
+enum swayc_layouts default_layout(struct sway_container *output);
+void sort_workspaces(struct sway_container *output);
 
 #endif
diff --git a/include/sway/workspace.h b/include/sway/workspace.h
new file mode 100644
index 00000000..04b2ea4e
--- /dev/null
+++ b/include/sway/workspace.h
@@ -0,0 +1,6 @@
+#ifndef _SWAY_WORKSPACE_H
+#define _SWAY_WORKSPACE_H
+
+char *workspace_next_name(const char *output_name);
+
+#endif
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt
index 9a92466c..6d520e76 100644
--- a/sway/CMakeLists.txt
+++ b/sway/CMakeLists.txt
@@ -14,8 +14,9 @@ add_executable(sway
     desktop/output.c
     desktop/xdg_shell_v6.c
 
-    tree/layout.c
     tree/container.c
+    tree/layout.c
+    tree/workspace.c
 
 	base64.c
 	main.c
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 54bcf478..ac79356a 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -5,6 +5,8 @@
 #include "sway/container.h"
 #include "sway/layout.h"
 #include "sway/output.h"
+#include "sway/workspace.h"
+#include "log.h"
 
 static swayc_t *new_swayc(enum swayc_types type) {
 	// next id starts at 1 because 0 is assigned to root_container in layout.c
@@ -27,8 +29,8 @@ static swayc_t *new_swayc(enum swayc_types type) {
 
 swayc_t *new_output(struct sway_output *sway_output) {
 	struct wlr_box size;
-	wlr_output_effective_resolution(sway_output->wlr_output,
-			&size.width, &size.height);
+	wlr_output_effective_resolution(
+			sway_output->wlr_output, &size.width, &size.height);
 	const char *name = sway_output->wlr_output->name;
 
 	swayc_t *output = new_swayc(C_OUTPUT);
@@ -39,7 +41,31 @@ swayc_t *new_output(struct sway_output *sway_output) {
 
 	add_child(&root_container, output);
 
-	// TODO: Create workspace
-
+	// Create workspace
+	char *ws_name = workspace_next_name(output->name);
+	sway_log(L_DEBUG, "Creating default workspace %s", ws_name);
+	new_workspace(output, ws_name);
+	free(ws_name);
 	return output;
 }
+
+swayc_t *new_workspace(swayc_t *output, const char *name) {
+	if (!sway_assert(output, "new_workspace called with null output")) {
+		return NULL;
+	}
+	sway_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
+	swayc_t *workspace = new_swayc(C_WORKSPACE);
+
+	workspace->x = output->x;
+	workspace->y = output->y;
+	workspace->width = output->width;
+	workspace->height = output->height;
+	workspace->name = !name ? NULL : strdup(name);
+	workspace->prev_layout = L_NONE;
+	workspace->layout = default_layout(output);
+	workspace->workspace_layout = default_layout(output);
+
+	add_child(output, workspace);
+	sort_workspaces(output);
+	return workspace;
+}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 06200bbf..5a70c570 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -1,5 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
+#include <ctype.h>
 #include <stdbool.h>
+#include <stdlib.h>
 #include <string.h>
 #include <wlr/types/wlr_output_layout.h>
 #include "sway/container.h"
@@ -33,3 +35,38 @@ void add_child(swayc_t *parent, swayc_t *child) {
 	}
 	*/
 }
+
+enum swayc_layouts default_layout(swayc_t *output) {
+	/* TODO WLR
+	if (config->default_layout != L_NONE) {
+		//return config->default_layout;
+	} else if (config->default_orientation != L_NONE) {
+		return config->default_orientation;
+	} else */if (output->width >= output->height) {
+		return L_HORIZ;
+	} else {
+		return L_VERT;
+	}
+}
+
+static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
+	swayc_t *a = *(void **)_a;
+	swayc_t *b = *(void **)_b;
+	int retval = 0;
+
+	if (isdigit(a->name[0]) && isdigit(b->name[0])) {
+		int a_num = strtol(a->name, NULL, 10);
+		int b_num = strtol(b->name, NULL, 10);
+		retval = (a_num < b_num) ? -1 : (a_num > b_num);
+	} else if (isdigit(a->name[0])) {
+		retval = -1;
+	} else if (isdigit(b->name[0])) {
+		retval = 1;
+	}
+
+	return retval;
+}
+
+void sort_workspaces(swayc_t *output) {
+	list_stable_sort(output->children, sort_workspace_cmp_qsort);
+}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
new file mode 100644
index 00000000..e8ed4102
--- /dev/null
+++ b/sway/tree/workspace.c
@@ -0,0 +1,26 @@
+#define _XOPEN_SOURCE 500
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "sway/container.h"
+#include "log.h"
+
+void next_name_map(swayc_t *ws, void *data) {
+	int *count = data;
+	++count;
+}
+
+char *workspace_next_name(const char *output_name) {
+	sway_log(L_DEBUG, "Workspace: Generating new workspace name for output %s",
+			output_name);
+	int count = 0;
+	next_name_map(&root_container, &count);
+	++count;
+	int len = snprintf(NULL, 0, "%d", count);
+	char *name = malloc(len + 1);
+	if (!sway_assert(name, "Failed to allocate workspace name")) {
+		return NULL;
+	}
+	snprintf(name, len + 1, "%d", count);
+	return name;
+}