diff --git a/src/commands.c b/src/commands.c
index 798e2f6c..0aaa123e 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1023,6 +1023,76 @@ void cmd_mode(I3_CMD, const char *mode) {
     ysuccess(true);
 }
 
+typedef struct user_output_name {
+    char *name;
+    TAILQ_ENTRY(user_output_name) user_output_names;
+} user_output_name;
+typedef TAILQ_HEAD(user_output_names_head, user_output_name) user_output_names_head;
+
+static void user_output_names_add(user_output_names_head *list, const char *name) {
+    if (strcmp(name, "next") == 0) {
+        /* "next" here works like a wildcard: It "expands" to all available
+         * outputs. */
+        Output *output;
+        TAILQ_FOREACH (output, &outputs, outputs) {
+            user_output_name *co = scalloc(sizeof(user_output_name), 1);
+            co->name = sstrdup(output_primary_name(output));
+            TAILQ_INSERT_TAIL(list, co, user_output_names);
+        }
+        return;
+    }
+
+    user_output_name *co = scalloc(sizeof(user_output_name), 1);
+    co->name = sstrdup(name);
+    TAILQ_INSERT_TAIL(list, co, user_output_names);
+    return;
+}
+
+static Output *user_output_names_find_next(user_output_names_head *names, Output *current_output) {
+    Output *target_output = NULL;
+    user_output_name *uo;
+    TAILQ_FOREACH (uo, names, user_output_names) {
+        if (strcasecmp(output_primary_name(current_output), uo->name) == 0) {
+            /* The current output is in the user list */
+            while (true) {
+                /* This corrupts the outer loop but it is ok since we are going
+                 * to break anyway. */
+                uo = TAILQ_NEXT(uo, user_output_names);
+                if (!uo) {
+                    /* We reached the end of the list. We should use the first
+                     * available output that, if it exists, is already saved in
+                     * target_output. */
+                    break;
+                }
+                Output *out = get_output_from_string(current_output, uo->name);
+                if (out) {
+                    return out;
+                }
+            }
+            break;
+        }
+        if (!target_output) {
+            /* The first available output from the list is used in 2 cases:
+             * 1. When we must wrap around the user list. For example, if user
+             * specifies outputs A B C and C is `current_output`.
+             * 2. When the current output is not in the user list. For example,
+             * user specifies A B C and D is `current_output`. */
+            target_output = get_output_from_string(current_output, uo->name);
+        }
+    }
+    return target_output;
+}
+
+static void user_output_names_free(user_output_names_head *names) {
+    user_output_name *uo;
+    while (!TAILQ_EMPTY(names)) {
+        uo = TAILQ_FIRST(names);
+        free(uo->name);
+        TAILQ_REMOVE(names, uo, user_output_names);
+        free(uo);
+    }
+}
+
 /*
  * Implementation of 'move [window|container|workspace] [to] output <strings>'.
  *
@@ -1031,40 +1101,21 @@ void cmd_move_con_to_output(I3_CMD, const char *name, bool move_workspace) {
     /* Initialize a data structure that is used to save multiple user-specified
      * output names since this function is called multiple types for each
      * command call. */
-    typedef struct user_output_name {
-        char *name;
-        TAILQ_ENTRY(user_output_name) user_output_names;
-    } user_output_name;
-    static TAILQ_HEAD(user_output_names_head, user_output_name) user_output_names = TAILQ_HEAD_INITIALIZER(user_output_names);
+    static user_output_names_head names = TAILQ_HEAD_INITIALIZER(names);
 
     if (name) {
-        if (strcmp(name, "next") == 0) {
-            /* "next" here works like a wildcard: It "expands" to all available
-             * outputs. */
-            Output *output;
-            TAILQ_FOREACH (output, &outputs, outputs) {
-                user_output_name *co = scalloc(sizeof(user_output_name), 1);
-                co->name = sstrdup(output_primary_name(output));
-                TAILQ_INSERT_TAIL(&user_output_names, co, user_output_names);
-            }
-            return;
-        }
-
-        user_output_name *co = scalloc(sizeof(user_output_name), 1);
-        co->name = sstrdup(name);
-        TAILQ_INSERT_TAIL(&user_output_names, co, user_output_names);
+        user_output_names_add(&names, name);
         return;
     }
 
     HANDLE_EMPTY_MATCH;
 
-    if (TAILQ_EMPTY(&user_output_names)) {
+    if (TAILQ_EMPTY(&names)) {
         yerror("At least one output must be specified");
         return;
     }
 
     bool success = false;
-    user_output_name *uo;
     owindow *current;
     TAILQ_FOREACH (current, &owindows, owindows) {
         Con *ws = con_get_workspace(current->con);
@@ -1073,41 +1124,7 @@ void cmd_move_con_to_output(I3_CMD, const char *name, bool move_workspace) {
         }
 
         Output *current_output = get_output_for_con(ws);
-
-        Output *target_output = NULL;
-        TAILQ_FOREACH (uo, &user_output_names, user_output_names) {
-            if (strcasecmp(output_primary_name(current_output), uo->name) == 0) {
-                /* The current output is in the user list */
-                while (true) {
-                    /* This corrupts the outer loop but it is ok since we are
-                     * going to break anyway. */
-                    uo = TAILQ_NEXT(uo, user_output_names);
-                    if (!uo) {
-                        /* We reached the end of the list. We should use the
-                         * first available output that, if it exists, is
-                         * already saved in target_output. */
-                        break;
-                    }
-                    Output *out = get_output_from_string(current_output, uo->name);
-                    if (out) {
-                        DLOG("Found next target for workspace %s from user list: %s\n", ws->name, uo->name);
-                        target_output = out;
-                        break;
-                    }
-                }
-                break;
-            }
-            if (!target_output) {
-                /* The first available output from the list is used in 2 cases:
-                 * 1. When we must wrap around the user list. For example, if
-                 * user specifies outputs A B C and C is `current_output`.
-                 * 2. When the current output is not in the user list. For
-                 * example, user specifies A B C and D is `current_output`.
-                 */
-                DLOG("Found first target for workspace %s from user list: %s\n", ws->name, uo->name);
-                target_output = get_output_from_string(current_output, uo->name);
-            }
-        }
+        Output *target_output = user_output_names_find_next(&names, current_output);
         if (target_output) {
             if (move_workspace) {
                 workspace_move_to_output(ws, target_output);
@@ -1117,13 +1134,7 @@ void cmd_move_con_to_output(I3_CMD, const char *name, bool move_workspace) {
             success = true;
         }
     }
-
-    while (!TAILQ_EMPTY(&user_output_names)) {
-        uo = TAILQ_FIRST(&user_output_names);
-        free(uo->name);
-        TAILQ_REMOVE(&user_output_names, uo, user_output_names);
-        free(uo);
-    }
+    user_output_names_free(&names);
 
     cmd_output->needs_tree_render = success;
     if (success) {