diff --git a/epicardium/main.c b/epicardium/main.c
index 6b6dd641b6daa4b71ed7fd0bc1c6e2d95639bd36..4fcc65b65fdb1d6fff65107a12ef7e0cf281052a 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -34,6 +34,8 @@ int main(void)
 
 	load_config();
 
+	migration_delete_app_launchers();
+
 	//LED feedback in case of dead display
 	epic_leds_set(11, 0, 0, 1);
 	epic_leds_set(12, 0, 0, 1);
diff --git a/epicardium/os/config.c b/epicardium/os/config.c
index 65897cb5f4872c87eddeeba3062e737b9f2a3e45..605dc890576d0143f7242212a8997300de7307ab 100644
--- a/epicardium/os/config.c
+++ b/epicardium/os/config.c
@@ -1,6 +1,5 @@
 #include "os/core.h"
 #include "os/config.h"
-#include "fs/filesystem.h"
 #include "epicardium.h"
 
 #include <assert.h>
diff --git a/epicardium/user_core/meson.build b/epicardium/user_core/meson.build
index daf7395fb8fa56fed1863c84113740f529713828..96e6d4ed466e3b4d59cf0a25bd497fe25a0d133a 100644
--- a/epicardium/user_core/meson.build
+++ b/epicardium/user_core/meson.build
@@ -2,4 +2,5 @@ user_core_sources = files(
   'dispatcher.c',
   'interrupts.c',
   'lifecycle.c',
+  'migration.c',
 )
diff --git a/epicardium/user_core/migration.c b/epicardium/user_core/migration.c
new file mode 100644
index 0000000000000000000000000000000000000000..1cd79803057923b31f0ae20226e9641d58cb1a62
--- /dev/null
+++ b/epicardium/user_core/migration.c
@@ -0,0 +1,50 @@
+#include "epicardium.h"
+#include "os/core.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void migration_delete_app_launchers(void)
+{
+	int fd = epic_file_opendir("/");
+
+	struct epic_stat entry;
+	for (;;) {
+		epic_file_readdir(fd, &entry);
+
+		if (entry.type == EPICSTAT_NONE) {
+			// End
+			break;
+		}
+
+		const char *dot = strrchr(entry.name, '.');
+		if (dot && !strcmp(dot, ".py")) {
+			const char launcher[] = "# Launcher script for ";
+			char launcher_buf[strlen(launcher)];
+
+			int fd = epic_file_open(entry.name, "r");
+
+			if (fd >= 0) {
+				int n = epic_file_read(
+					fd, launcher_buf, sizeof(launcher_buf)
+				);
+				epic_file_close(fd);
+
+				if (n == (int)sizeof(launcher_buf) &&
+				    !memcmp(launcher,
+					    launcher_buf,
+					    sizeof(launcher_buf))) {
+					LOG_INFO(
+						"migration",
+						"Delete old launcher %s",
+						entry.name
+					);
+					epic_file_unlink(entry.name);
+				}
+			}
+		}
+	}
+
+	epic_file_close(fd);
+}
diff --git a/epicardium/user_core/user_core.h b/epicardium/user_core/user_core.h
index 5b090e6f90d106b9471160e459e27b6c47d88362..64a2f1f15a092eaa298f64b5f2ed099c92c1a1d4 100644
--- a/epicardium/user_core/user_core.h
+++ b/epicardium/user_core/user_core.h
@@ -12,3 +12,6 @@ extern TaskHandle_t dispatcher_task_id;
 /* ---------- Lifecycle ---------------------------------------------------- */
 void vLifecycleTask(void *pvParameters);
 void return_to_menu(void);
+
+/* ---------- Migration ---------------------------------------------------- */
+void migration_delete_app_launchers(void);