Index: uspace/app/copy/copy.c
===================================================================
--- uspace/app/copy/copy.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/copy/copy.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -155,4 +155,7 @@
 	case fmgt_io_create:
 		fmt = "Error creating %s. (%s)\n";
+		break;
+	case fmgt_io_delete:
+		fmt = "Error deleting %s. (%s)\n";
 		break;
 	case fmgt_io_open:
Index: uspace/app/meson.build
===================================================================
--- uspace/app/meson.build	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/meson.build	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 #
-# Copyright (c) 2025 Jiri Svoboda
+# Copyright (c) 2026 Jiri Svoboda
 # Copyright (c) 2019 Jiří Zárevúcky
 # All rights reserved.
@@ -69,4 +69,5 @@
 	'mkmfs',
 	'modplay',
+	'move',
 	'nav',
 	'netecho',
Index: uspace/app/move/doc/doxygroups.h
===================================================================
--- uspace/app/move/doc/doxygroups.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/move/doc/doxygroups.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,4 @@
+/** @addtogroup move move
+ * @brief Move files and directories.
+ * @ingroup apps
+ */
Index: uspace/app/move/meson.build
===================================================================
--- uspace/app/move/meson.build	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/move/meson.build	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2026 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+deps = [ 'console', 'fmgt', 'input' ]
+src = files('move.c')
Index: uspace/app/move/move.c
===================================================================
--- uspace/app/move/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/move/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup move
+ * @{
+ */
+/** @file Move files and directories.
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <io/console.h>
+#include <io/cons_event.h>
+#include <io/kbd_event.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
+
+#define NAME  "move"
+
+static bool move_abort_query(void *);
+static void move_progress(void *, fmgt_progress_t *);
+static fmgt_error_action_t move_io_error_query(void *, fmgt_io_error_t *);
+static fmgt_exists_action_t move_exists_query(void *, fmgt_exists_t *);
+
+static bool prog_upd = false;
+static bool nonint = false;
+static bool quiet = false;
+
+static console_ctrl_t *con;
+
+static fmgt_cb_t move_fmgt_cb = {
+	.abort_query = move_abort_query,
+	.io_error_query = move_io_error_query,
+	.exists_query = move_exists_query,
+	.progress = move_progress,
+};
+
+static void print_syntax(void)
+{
+	printf("Move files and directories.\n");
+	printf("Syntax: %s [<options] <source>... <dest>\n", NAME);
+	printf("\t-h    help\n");
+	printf("\t-n    non-interactive\n");
+	printf("\t-q    quiet\n");
+}
+
+/** Called by fmgt to query for user abort.
+ *
+ * @param arg Argument (not used)
+ * @return @c true iff user requested abort
+ */
+static bool move_abort_query(void *arg)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	errno_t rc;
+	usec_t timeout;
+
+	if (con == NULL)
+		return false;
+
+	timeout = 0;
+	rc = console_get_event_timeout(con, &event, &timeout);
+	if (rc != EOK)
+		return false;
+
+	if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+		ev = &event.ev.key;
+		if ((ev->mods & KM_ALT) == 0 &&
+		    (ev->mods & KM_SHIFT) == 0 &&
+		    (ev->mods & KM_CTRL) != 0) {
+			if (ev->key == KC_C)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/** Called by fmgt to give the user progress update.
+ *
+ * @param arg Argument (not used)
+ * @param progress Progress report
+ */
+static void move_progress(void *arg, fmgt_progress_t *progress)
+{
+	(void)arg;
+
+	if (!quiet) {
+		printf("\rCopied %s files, %s; current file: %s done.  "
+		    "\b\b", progress->total_procf, progress->total_procb,
+		    progress->curf_percent);
+		fflush(stdout);
+		prog_upd = true;
+	}
+}
+
+/** Called by fmgt to let user choose I/O error recovery action.
+ *
+ * @param arg Argument (not used)
+ * @param err I/O error report
+ * @return Error recovery action.
+ */
+static fmgt_error_action_t move_io_error_query(void *arg,
+    fmgt_io_error_t *err)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	const char *fmt = NULL;
+	errno_t rc;
+
+	(void)arg;
+
+	if (nonint)
+		return fmgt_er_abort;
+
+	if (prog_upd)
+		putchar('\n');
+
+	switch (err->optype) {
+	case fmgt_io_read:
+		fmt = "Error reading file %s. (%s)\n";
+		break;
+	case fmgt_io_write:
+		fmt = "Error writing file %s. (%s)\n";
+		break;
+	case fmgt_io_create:
+		fmt = "Error creating %s. (%s)\n";
+		break;
+	case fmgt_io_delete:
+		fmt = "Error deleting %s. (%s)\n";
+		break;
+	case fmgt_io_open:
+		fmt = "Error opening %s. (%s)\n";
+		break;
+	}
+
+	fprintf(stderr, fmt, err->fname, str_error(err->rc));
+	fprintf(stderr, "[A]bort or [R]etry?\n");
+
+	if (con == NULL)
+		return fmgt_er_abort;
+
+	while (true) {
+		rc = console_get_event(con, &event);
+		if (rc != EOK)
+			return fmgt_er_abort;
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_CTRL) == 0) {
+				if (ev->c == 'r' || ev->c == 'R')
+					return fmgt_er_retry;
+				if (ev->c == 'a' || ev->c == 'A')
+					return fmgt_er_abort;
+			}
+		}
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_SHIFT) == 0 &&
+			    (ev->mods & KM_CTRL) != 0) {
+				if (ev->key == KC_C)
+					return fmgt_er_abort;
+			}
+		}
+	}
+}
+
+/** Called by fmgt to let user choose destination exists recovery action.
+ *
+ * @param arg Argument (not used)
+ * @param err I/O error report
+ * @return Error recovery action.
+ */
+static fmgt_exists_action_t move_exists_query(void *arg, fmgt_exists_t *exists)
+{
+	cons_event_t event;
+	kbd_event_t *ev;
+	errno_t rc;
+
+	(void)arg;
+
+	if (nonint)
+		return fmgt_exr_fail;
+
+	if (prog_upd)
+		putchar('\n');
+
+	fprintf(stderr, "File %s exists.\n", exists->fname);
+	fprintf(stderr, "[O]verwrite, [S]kip or [A]bort?\n");
+
+	if (con == NULL)
+		return fmgt_exr_abort;
+
+	while (true) {
+		rc = console_get_event(con, &event);
+		if (rc != EOK)
+			return fmgt_exr_abort;
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_CTRL) == 0) {
+				if (ev->c == 'o' || ev->c == 'O')
+					return fmgt_exr_overwrite;
+				if (ev->c == 's' || ev->c == 'S')
+					return fmgt_exr_skip;
+				if (ev->c == 'a' || ev->c == 'A')
+					return fmgt_exr_abort;
+			}
+		}
+
+		if (event.type == CEV_KEY && event.ev.key.type == KEY_PRESS) {
+			ev = &event.ev.key;
+			if ((ev->mods & KM_ALT) == 0 &&
+			    (ev->mods & KM_SHIFT) == 0 &&
+			    (ev->mods & KM_CTRL) != 0) {
+				if (ev->key == KC_C)
+					return fmgt_exr_abort;
+			}
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	fmgt_t *fmgt = NULL;
+	errno_t rc;
+	int i;
+	fmgt_flist_t *flist = NULL;
+	const char *dest;
+
+	rc = fmgt_flist_create(&flist);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		goto error;
+	}
+
+	con = console_init(stdin, stdout);
+
+	i = 1;
+	while (i < argc && argv[i][0] == '-') {
+		if (str_cmp(argv[i], "-h") == 0) {
+			print_syntax();
+			return 0;
+		} else if (str_cmp(argv[i], "-n") == 0) {
+			++i;
+			nonint = true;
+		} else if (str_cmp(argv[i], "-q") == 0) {
+			++i;
+			quiet = true;
+		} else {
+			printf("Invalid option '%s'.\n", argv[i]);
+			print_syntax();
+			goto error;
+		}
+	}
+
+	/* Need at least one source and one destination. */
+	if (i + 1 >= argc) {
+		print_syntax();
+		goto error;
+	}
+
+	/* All arguments except the last one are sources. */
+	do {
+		rc = fmgt_flist_append(flist, argv[i++]);
+		if (rc != EOK) {
+			printf("Out of memory.\n");
+			goto error;
+		}
+	} while (i + 1 < argc);
+
+	dest = argv[i];
+
+	rc = fmgt_create(&fmgt);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		goto error;
+	}
+
+	fmgt_set_cb(fmgt, &move_fmgt_cb, NULL);
+
+	rc = fmgt_move(fmgt, flist, dest);
+	if (prog_upd)
+		putchar('\n');
+	if (rc != EOK) {
+		printf("Error moving file(s): %s.\n", str_error(rc));
+		goto error;
+	}
+
+	fmgt_flist_destroy(flist);
+	fmgt_destroy(fmgt);
+	return 0;
+error:
+	if (flist != NULL)
+		fmgt_flist_destroy(flist);
+	if (fmgt != NULL)
+		fmgt_destroy(fmgt);
+	return 1;
+}
+
+/** @}
+ */
Index: uspace/app/nav/dlg/copydlg.c
===================================================================
--- uspace/app/nav/dlg/copydlg.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/dlg/copydlg.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -277,7 +277,7 @@
 }
 
-/** Destroy new file dialog.
- *
- * @param dialog New file dialog or @c NULL
+/** Destroy copy dialog.
+ *
+ * @param dialog Copy dialog or @c NULL
  */
 void copy_dlg_destroy(copy_dlg_t *dialog)
@@ -290,7 +290,7 @@
 }
 
-/** Set new file dialog callback.
- *
- * @param dialog new file dialog
+/** Set copy dialog callback.
+ *
+ * @param dialog Copy dialog
  * @param cb New file dialog callbacks
  * @param arg Callback argument
@@ -303,5 +303,5 @@
 }
 
-/** New file dialog window close handler.
+/** Copy dialog window close handler.
  *
  * @param window Window
@@ -318,5 +318,5 @@
 }
 
-/** New file dialog window keyboard event handler.
+/** Copy dialog window keyboard event handler.
  *
  * @param window Window
@@ -349,5 +349,5 @@
 }
 
-/** New file dialog OK button click handler.
+/** Copy dialog OK button click handler.
  *
  * @param pbutton Push button
@@ -363,5 +363,5 @@
 }
 
-/** New file dialog cancel button click handler.
+/** Copy dialog cancel button click handler.
  *
  * @param pbutton Push button
Index: uspace/app/nav/dlg/movedlg.c
===================================================================
--- uspace/app/nav/dlg/movedlg.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/dlg/movedlg.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Move dialog
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <mem.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <ui/fixed.h>
+#include <ui/label.h>
+#include <ui/pbutton.h>
+#include <ui/resource.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+#include "movedlg.h"
+
+static void move_dlg_wnd_close(ui_window_t *, void *);
+static void move_dlg_wnd_kbd(ui_window_t *, void *, kbd_event_t *);
+
+ui_window_cb_t move_dlg_wnd_cb = {
+	.close = move_dlg_wnd_close,
+	.kbd = move_dlg_wnd_kbd
+};
+
+static void move_dlg_bok_clicked(ui_pbutton_t *, void *);
+static void move_dlg_bcancel_clicked(ui_pbutton_t *, void *);
+
+ui_pbutton_cb_t move_dlg_bok_cb = {
+	.clicked = move_dlg_bok_clicked
+};
+
+ui_pbutton_cb_t move_dlg_bcancel_cb = {
+	.clicked = move_dlg_bcancel_clicked
+};
+
+/** Create Move dialog.
+ *
+ * @param ui User interface
+ * @param flist List of files to move (ownership transferred)
+ * @param dest Pre-filled dstination path
+ * @param rdialog Place to store pointer to new dialog
+ * @return EOK on success or an error code
+ */
+errno_t move_dlg_create(ui_t *ui, fmgt_flist_t *flist, const char *dest,
+    move_dlg_t **rdialog)
+{
+	errno_t rc;
+	move_dlg_t *dialog;
+	ui_window_t *window = NULL;
+	ui_wnd_params_t wparams;
+	ui_fixed_t *fixed = NULL;
+	ui_label_t *label = NULL;
+	ui_entry_t *edest = NULL;
+	ui_pbutton_t *bok = NULL;
+	ui_pbutton_t *bcancel = NULL;
+	gfx_rect_t rect;
+	ui_resource_t *ui_res;
+	fmgt_flist_entry_t *entry;
+	char *tmove = NULL;
+	unsigned count;
+
+	dialog = calloc(1, sizeof(move_dlg_t));
+	if (dialog == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	ui_wnd_params_init(&wparams);
+	wparams.caption = "Move";
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 40;
+		wparams.rect.p1.y = 9;
+	} else {
+		wparams.rect.p0.x = 0;
+		wparams.rect.p0.y = 0;
+		wparams.rect.p1.x = 300;
+		wparams.rect.p1.y = 155;
+	}
+
+	rc = ui_window_create(ui, &wparams, &window);
+	if (rc != EOK)
+		goto error;
+
+	ui_window_set_cb(window, &move_dlg_wnd_cb, dialog);
+
+	ui_res = ui_window_get_res(window);
+
+	rc = ui_fixed_create(&fixed);
+	if (rc != EOK)
+		goto error;
+
+	count = fmgt_flist_count(flist);
+	if (count == 1) {
+		entry = fmgt_flist_first(flist);
+		rc = asprintf(&tmove, "Move \"%s\" to:",
+		    entry->fname);
+	} else {
+		rc = asprintf(&tmove, "Move %u files/directories to:",
+		    count);
+	}
+
+	rc = ui_label_create(ui_res, tmove, &label);
+	if (rc != EOK)
+		goto error;
+
+	free(tmove);
+	tmove = NULL;
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 3;
+		rect.p0.y = 2;
+		rect.p1.x = 17;
+		rect.p1.y = 3;
+	} else {
+		rect.p0.x = 10;
+		rect.p0.y = 35;
+		rect.p1.x = 190;
+		rect.p1.y = 50;
+	}
+
+	ui_label_set_rect(label, &rect);
+
+	rc = ui_fixed_add(fixed, ui_label_ctl(label));
+	if (rc != EOK)
+		goto error;
+
+	label = NULL;
+
+	rc = ui_entry_create(window, dest, &edest);
+	if (rc != EOK)
+		goto error;
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 3;
+		rect.p0.y = 3;
+		rect.p1.x = 37;
+		rect.p1.y = 4;
+	} else {
+		rect.p0.x = 10;
+		rect.p0.y = 55;
+		rect.p1.x = 290;
+		rect.p1.y = 80;
+	}
+
+	ui_entry_set_rect(edest, &rect);
+
+	rc = ui_fixed_add(fixed, ui_entry_ctl(edest));
+	if (rc != EOK)
+		goto error;
+
+	dialog->edest = edest;
+	edest = NULL;
+
+	rc = ui_pbutton_create(ui_res, "OK", &bok);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(bok, &move_dlg_bok_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 10;
+		rect.p0.y = 6;
+		rect.p1.x = 20;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 55;
+		rect.p0.y = 120;
+		rect.p1.x = 145;
+		rect.p1.y = 148;
+	}
+
+	ui_pbutton_set_rect(bok, &rect);
+
+	ui_pbutton_set_default(bok, true);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(bok));
+	if (rc != EOK)
+		goto error;
+
+	dialog->bok = bok;
+	bok = NULL;
+
+	rc = ui_pbutton_create(ui_res, "Cancel", &bcancel);
+	if (rc != EOK)
+		goto error;
+
+	ui_pbutton_set_cb(bcancel, &move_dlg_bcancel_cb, dialog);
+
+	/* FIXME: Auto layout */
+	if (ui_is_textmode(ui)) {
+		rect.p0.x = 22;
+		rect.p0.y = 6;
+		rect.p1.x = 32;
+		rect.p1.y = 7;
+	} else {
+		rect.p0.x = 155;
+		rect.p0.y = 120;
+		rect.p1.x = 245;
+		rect.p1.y = 148;
+	}
+
+	ui_pbutton_set_rect(bcancel, &rect);
+
+	rc = ui_fixed_add(fixed, ui_pbutton_ctl(bcancel));
+	if (rc != EOK)
+		goto error;
+
+	dialog->bcancel = bcancel;
+	bcancel = NULL;
+
+	ui_window_add(window, ui_fixed_ctl(fixed));
+	fixed = NULL;
+
+	rc = ui_window_paint(window);
+	if (rc != EOK)
+		goto error;
+
+	dialog->window = window;
+	dialog->flist = flist;
+	*rdialog = dialog;
+	return EOK;
+error:
+	if (tmove != NULL)
+		free(tmove);
+	if (bok != NULL)
+		ui_pbutton_destroy(bok);
+	if (bcancel != NULL)
+		ui_pbutton_destroy(bcancel);
+	if (label != NULL)
+		ui_label_destroy(label);
+	if (fixed != NULL)
+		ui_fixed_destroy(fixed);
+	if (window != NULL)
+		ui_window_destroy(window);
+	if (dialog != NULL)
+		free(dialog);
+	return rc;
+}
+
+/** Destroy move dialog.
+ *
+ * @param dialog Move dialog or @c NULL
+ */
+void move_dlg_destroy(move_dlg_t *dialog)
+{
+	if (dialog == NULL)
+		return;
+
+	ui_window_destroy(dialog->window);
+	free(dialog);
+}
+
+/** Set Move dialog callback.
+ *
+ * @param dialog Move dialog
+ * @param cb Move dialog callbacks
+ * @param arg Callback argument
+ */
+void move_dlg_set_cb(move_dlg_t *dialog, move_dlg_cb_t *cb,
+    void *arg)
+{
+	dialog->cb = cb;
+	dialog->arg = arg;
+}
+
+/** Move dialog window close handler.
+ *
+ * @param window Window
+ * @param arg Argument (move_dlg_t *)
+ */
+static void move_dlg_wnd_close(ui_window_t *window, void *arg)
+{
+	move_dlg_t *dialog = (move_dlg_t *) arg;
+
+	(void)window;
+	if (dialog->cb != NULL && dialog->cb->close != NULL) {
+		dialog->cb->close(dialog, dialog->arg);
+	}
+}
+
+/** Move dialog window keyboard event handler.
+ *
+ * @param window Window
+ * @param arg Argument (move_dlg_t *)
+ * @param event Keyboard event
+ */
+static void move_dlg_wnd_kbd(ui_window_t *window, void *arg,
+    kbd_event_t *event)
+{
+	move_dlg_t *dialog = (move_dlg_t *) arg;
+
+	if (event->type == KEY_PRESS &&
+	    (event->mods & (KM_CTRL | KM_SHIFT | KM_ALT)) == 0) {
+		if (event->key == KC_ENTER) {
+			/* Confirm */
+			if (dialog->cb != NULL && dialog->cb->bok != NULL) {
+				dialog->cb->bok(dialog, dialog->arg);
+				return;
+			}
+		} else if (event->key == KC_ESCAPE) {
+			/* Cancel */
+			if (dialog->cb != NULL && dialog->cb->bcancel != NULL) {
+				dialog->cb->bcancel(dialog, dialog->arg);
+				return;
+			}
+		}
+	}
+
+	ui_window_def_kbd(window, event);
+}
+
+/** Move dialog OK button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (move_dlg_t *)
+ */
+static void move_dlg_bok_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	move_dlg_t *dialog = (move_dlg_t *) arg;
+
+	if (dialog->cb != NULL && dialog->cb->bok != NULL) {
+		dialog->cb->bok(dialog, dialog->arg);
+	}
+}
+
+/** Move dialog cancel button click handler.
+ *
+ * @param pbutton Push button
+ * @param arg Argument (move_dlg_t *)
+ */
+static void move_dlg_bcancel_clicked(ui_pbutton_t *pbutton, void *arg)
+{
+	move_dlg_t *dialog = (move_dlg_t *) arg;
+
+	(void)pbutton;
+	if (dialog->cb != NULL && dialog->cb->bcancel != NULL) {
+		dialog->cb->bcancel(dialog, dialog->arg);
+	}
+}
+
+/** @}
+ */
Index: uspace/app/nav/dlg/movedlg.h
===================================================================
--- uspace/app/nav/dlg/movedlg.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/dlg/movedlg.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Move dialog
+ */
+
+#ifndef DLG_MOVEDLG_H
+#define DLG_MOVEDLG_H
+
+#include <errno.h>
+#include <fmgt.h>
+#include <types/ui/ui.h>
+#include "../types/dlg/movedlg.h"
+
+extern errno_t move_dlg_create(ui_t *, fmgt_flist_t *, const char *,
+    move_dlg_t **);
+extern void move_dlg_set_cb(move_dlg_t *, move_dlg_cb_t *,
+    void *);
+extern void move_dlg_destroy(move_dlg_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/menu.c
===================================================================
--- uspace/app/nav/menu.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/menu.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -59,4 +59,5 @@
 	ui_menu_entry_t *mverify;
 	ui_menu_entry_t *mcopy;
+	ui_menu_entry_t *mmove;
 	ui_menu_entry_t *mfsep;
 	ui_menu_entry_t *mexit;
@@ -111,4 +112,10 @@
 	ui_menu_entry_set_cb(mcopy, nav_menu_file_copy, (void *) menu);
 
+	rc = ui_menu_entry_create(mfile, "~M~ove", "Ctrl-X", &mmove);
+	if (rc != EOK)
+		goto error;
+
+	ui_menu_entry_set_cb(mmove, nav_menu_file_move, (void *) menu);
+
 	rc = ui_menu_entry_sep_create(mfile, &mfsep);
 	if (rc != EOK)
@@ -234,4 +241,17 @@
 }
 
+/** File / Move menu entry selected.
+ *
+ * @param mentry Menu entry
+ * @param arg Argument (navigator_t *)
+ */
+void nav_menu_file_move(ui_menu_entry_t *mentry, void *arg)
+{
+	nav_menu_t *menu = (nav_menu_t *)arg;
+
+	if (menu->cb != NULL && menu->cb->file_move != NULL)
+		menu->cb->file_move(menu->cb_arg);
+}
+
 /** File / Exit menu entry selected.
  *
Index: uspace/app/nav/menu.h
===================================================================
--- uspace/app/nav/menu.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/menu.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -51,4 +51,5 @@
 extern void nav_menu_file_verify(ui_menu_entry_t *, void *);
 extern void nav_menu_file_copy(ui_menu_entry_t *, void *);
+extern void nav_menu_file_move(ui_menu_entry_t *, void *);
 extern void nav_menu_file_exit(ui_menu_entry_t *, void *);
 
Index: uspace/app/nav/meson.build
===================================================================
--- uspace/app/nav/meson.build	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/meson.build	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -32,4 +32,5 @@
 	'dlg/existsdlg.c',
 	'dlg/ioerrdlg.c',
+	'dlg/movedlg.c',
 	'dlg/newfiledlg.c',
 	'dlg/progress.c',
@@ -38,4 +39,5 @@
 	'main.c',
 	'menu.c',
+	'move.c',
 	'nav.c',
 	'newfile.c',
@@ -48,4 +50,5 @@
 	'dlg/existsdlg.c',
 	'dlg/ioerrdlg.c',
+	'dlg/movedlg.c',
 	'dlg/newfiledlg.c',
 	'dlg/progress.c',
@@ -53,4 +56,5 @@
 	'copy.c',
 	'menu.c',
+	'move.c',
 	'nav.c',
 	'newfile.c',
@@ -60,4 +64,5 @@
 	'test/dlg/existsdlg.c',
 	'test/dlg/ioerrdlg.c',
+	'test/dlg/movedlg.c',
 	'test/dlg/newfiledlg.c',
 	'test/dlg/progress.c',
Index: uspace/app/nav/move.c
===================================================================
--- uspace/app/nav/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Move Files.
+ */
+
+#include <fmgt.h>
+#include <stdlib.h>
+#include <str_error.h>
+#include <ui/fixed.h>
+#include <ui/filelist.h>
+#include <ui/msgdialog.h>
+#include <ui/resource.h>
+#include <ui/ui.h>
+#include <ui/window.h>
+#include <stdbool.h>
+#include <str.h>
+#include "dlg/movedlg.h"
+#include "dlg/progress.h"
+#include "menu.h"
+#include "move.h"
+#include "nav.h"
+#include "types/move.h"
+#include "panel.h"
+
+static void move_bok(move_dlg_t *, void *);
+static void move_bcancel(move_dlg_t *, void *);
+static void move_close(move_dlg_t *, void *);
+
+static move_dlg_cb_t move_cb = {
+	.bok = move_bok,
+	.bcancel = move_bcancel,
+	.close = move_close
+};
+
+static bool move_abort_query(void *);
+static void move_progress(void *, fmgt_progress_t *);
+
+static fmgt_cb_t move_fmgt_cb = {
+	.abort_query = move_abort_query,
+	.io_error_query = navigator_io_error_query,
+	.exists_query = navigator_exists_query,
+	.progress = move_progress,
+};
+
+/** Open Move dialog.
+ *
+ * @param navigator Navigator
+ * @param flist File list
+ */
+void navigator_move_dlg(navigator_t *navigator, fmgt_flist_t *flist)
+{
+	move_dlg_t *dlg;
+	panel_t *dpanel;
+	char *dest;
+	errno_t rc;
+
+	/* Get destination panel. */
+	dpanel = navigator_get_inactive_panel(navigator);
+	if (dpanel == NULL) {
+		/* out of memory */
+		return;
+	}
+
+	/* Get destination path from destination panel. */
+	dest = panel_get_dir(dpanel);
+	if (dest == NULL) {
+		/* out of memory */
+		return;
+	}
+
+	rc = move_dlg_create(navigator->ui, flist, dest, &dlg);
+	if (rc != EOK) {
+		free(dest);
+		return;
+	}
+
+	move_dlg_set_cb(dlg, &move_cb, (void *)navigator);
+	free(dest);
+}
+
+/** Move worker function.
+ *
+ * @param arg Argument (navigator_move_job_t)
+ */
+static void move_wfunc(void *arg)
+{
+	fmgt_t *fmgt = NULL;
+	navigator_move_job_t *job = (navigator_move_job_t *)arg;
+	char *msg = NULL;
+	navigator_t *nav = job->navigator;
+	ui_msg_dialog_t *dialog = NULL;
+	ui_msg_dialog_params_t params;
+	errno_t rc;
+	int rv;
+
+	rc = fmgt_create(&fmgt);
+	if (rc != EOK) {
+		/* out of memory */
+		return;
+	}
+
+	fmgt_set_cb(fmgt, &move_fmgt_cb, (void *)nav);
+	fmgt_set_init_update(fmgt, true);
+
+	rc = fmgt_move(fmgt, job->flist, job->dest);
+	if (rc != EOK) {
+		rv = asprintf(&msg, "Error moving file(s) (%s).",
+		    str_error(rc));
+		if (rv < 0)
+			return;
+		goto error;
+	}
+
+	fmgt_destroy(fmgt);
+	ui_lock(nav->ui);
+	progress_dlg_destroy(nav->progress_dlg);
+	navigator_refresh_panels(nav);
+	ui_unlock(nav->ui);
+	fmgt_flist_destroy(job->flist);
+	free(job);
+	return;
+error:
+	fmgt_destroy(fmgt);
+	ui_lock(nav->ui);
+	progress_dlg_destroy(nav->progress_dlg);
+	navigator_refresh_panels(nav);
+	ui_msg_dialog_params_init(&params);
+	params.caption = "Error";
+	params.text = msg;
+	(void) ui_msg_dialog_create(nav->ui, &params, &dialog);
+	ui_unlock(nav->ui);
+	free(msg);
+}
+
+/** Move dialog confirmed.
+ *
+ * @param dlg Move dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void move_bok(move_dlg_t *dlg, void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+	ui_msg_dialog_t *dialog = NULL;
+	navigator_move_job_t *job;
+	ui_msg_dialog_params_t params;
+	progress_dlg_params_t pd_params;
+	char *msg = NULL;
+	errno_t rc;
+
+	job = calloc(1, sizeof(navigator_move_job_t));
+	if (job == NULL)
+		return;
+
+	job->navigator = nav;
+	job->flist = dlg->flist;
+	job->dest = str_dup(ui_entry_get_text(dlg->edest));
+	if (job->dest == NULL) {
+		free(job);
+		return;
+	}
+
+	move_dlg_destroy(dlg);
+	dlg->flist = NULL;
+
+	progress_dlg_params_init(&pd_params);
+	pd_params.caption = "Moving";
+
+	rc = progress_dlg_create(nav->ui, &pd_params, &nav->progress_dlg);
+	if (rc != EOK) {
+		msg = str_dup("Out of memory.");
+		if (msg == NULL)
+			return;
+		goto error;
+	}
+
+	progress_dlg_set_cb(nav->progress_dlg, &navigator_progress_cb,
+	    (void *)nav);
+
+	rc = navigator_worker_start(nav, move_wfunc, (void *)job);
+	if (rc != EOK) {
+		msg = str_dup("Out of memory.");
+		if (msg == NULL)
+			return;
+		goto error;
+	}
+
+	return;
+error:
+	ui_msg_dialog_params_init(&params);
+	params.caption = "Error";
+	params.text = msg;
+	(void) ui_msg_dialog_create(nav->ui, &params, &dialog);
+	free(msg);
+}
+
+/** New file dialog cancelled.
+ *
+ * @param dlg New file dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void move_bcancel(move_dlg_t *dlg, void *arg)
+{
+	(void)arg;
+	move_dlg_destroy(dlg);
+}
+
+/** New file dialog closed.
+ *
+ * @param dlg New file dialog
+ * @param arg Argument (navigator_t *)
+ */
+static void move_close(move_dlg_t *dlg, void *arg)
+{
+	(void)arg;
+	move_dlg_destroy(dlg);
+}
+
+/** New file abort query.
+ *
+ * @param arg Argument (navigator_t *)
+ * @return @c true iff abort is requested
+ */
+static bool move_abort_query(void *arg)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	return nav->abort_op;
+}
+
+/** New file progress update.
+ *
+ * @param arg Argument (navigator_t *)
+ * @param progress Progress update
+ */
+static void move_progress(void *arg, fmgt_progress_t *progress)
+{
+	navigator_t *nav = (navigator_t *)arg;
+
+	progress_dlg_set_progress(nav->progress_dlg, progress);
+}
+
+/** @}
+ */
Index: uspace/app/nav/move.h
===================================================================
--- uspace/app/nav/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Move Files
+ */
+
+#ifndef MOVE_H
+#define MOVE_H
+
+#include <fmgt.h>
+#include "types/nav.h"
+
+extern void navigator_move_dlg(navigator_t *, fmgt_flist_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/nav.c
===================================================================
--- uspace/app/nav/nav.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/nav.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -52,4 +52,5 @@
 #include "dlg/ioerrdlg.h"
 #include "menu.h"
+#include "move.h"
 #include "newfile.h"
 #include "nav.h"
@@ -72,4 +73,5 @@
 static void navigator_file_verify(void *);
 static void navigator_file_copy(void *);
+static void navigator_file_move(void *);
 static void navigator_file_exit(void *);
 
@@ -80,4 +82,5 @@
 	.file_verify = navigator_file_verify,
 	.file_copy = navigator_file_copy,
+	.file_move = navigator_file_move,
 	.file_exit = navigator_file_exit
 };
@@ -160,4 +163,7 @@
 			navigator_file_copy((void *)navigator);
 			break;
+		case KC_X:
+			navigator_file_move((void *)navigator);
+			break;
 		case KC_Q:
 			ui_quit(navigator->ui);
@@ -630,4 +636,33 @@
 	/* flist ownership transferred */
 	navigator_copy_dlg(navigator, flist);
+}
+
+/** File / Move menu entry selected */
+static void navigator_file_move(void *arg)
+{
+	navigator_t *navigator = (navigator_t *)arg;
+
+	ui_file_list_entry_t *entry;
+	ui_file_list_entry_attr_t attr;
+	fmgt_flist_t *flist;
+	panel_t *panel;
+	errno_t rc;
+
+	panel = navigator_get_active_panel(navigator);
+	entry = ui_file_list_get_cursor(panel->flist);
+	ui_file_list_entry_get_attr(entry, &attr);
+
+	rc = fmgt_flist_create(&flist);
+	if (rc != EOK)
+		return;
+
+	rc = fmgt_flist_append(flist, attr.name);
+	if (rc != EOK) {
+		fmgt_flist_destroy(flist);
+		return;
+	}
+
+	/* flist ownership transferred */
+	navigator_move_dlg(navigator, flist);
 }
 
@@ -783,4 +818,7 @@
 		fmt = "Error creating %s.";
 		break;
+	case fmgt_io_delete:
+		fmt = "Error deleting %s.";
+		break;
 	}
 
Index: uspace/app/nav/test/dlg/movedlg.c
===================================================================
--- uspace/app/nav/test/dlg/movedlg.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/test/dlg/movedlg.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <pcut/pcut.h>
+#include <ui/ui.h>
+#include "../../dlg/movedlg.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(movedlg);
+
+static move_dlg_cb_t move_dlg_cb;
+
+/** Create and destroy move dialog. */
+PCUT_TEST(create_destroy)
+{
+	ui_t *ui;
+	move_dlg_t *dlg = NULL;
+	fmgt_flist_t *flist;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_create(&flist);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = move_dlg_create(ui, flist, "foo", &dlg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(dlg);
+
+	move_dlg_destroy(dlg);
+
+	fmgt_flist_destroy(flist);
+	ui_destroy(ui);
+}
+
+/** Set callbacks for move dialog. */
+PCUT_TEST(set_cb)
+{
+	ui_t *ui;
+	move_dlg_t *dlg = NULL;
+	fmgt_flist_t *flist;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_create(&flist);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = move_dlg_create(ui, flist, "foo", &dlg);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(dlg);
+
+	move_dlg_set_cb(dlg, &move_dlg_cb, NULL);
+
+	move_dlg_destroy(dlg);
+
+	fmgt_flist_destroy(flist);
+	ui_destroy(ui);
+}
+
+PCUT_EXPORT(movedlg);
Index: uspace/app/nav/test/main.c
===================================================================
--- uspace/app/nav/test/main.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/test/main.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -38,4 +38,5 @@
 PCUT_IMPORT(verifydlg);
 PCUT_IMPORT(menu);
+PCUT_IMPORT(movedlg);
 PCUT_IMPORT(nav);
 PCUT_IMPORT(panel);
Index: uspace/app/nav/types/dlg/copydlg.h
===================================================================
--- uspace/app/nav/types/dlg/copydlg.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/types/dlg/copydlg.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,6 +34,6 @@
  */
 
-#ifndef TYPES_DLG_VERIFYDLG_H
-#define TYPES_DLG_VERIFYDLG_H
+#ifndef TYPES_DLG_COPYDLG_H
+#define TYPES_DLG_COPYDLG_H
 
 #include <errno.h>
Index: uspace/app/nav/types/dlg/movedlg.h
===================================================================
--- uspace/app/nav/types/dlg/movedlg.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/types/dlg/movedlg.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Move dialog
+ */
+
+#ifndef TYPES_DLG_MOVEDLG_H
+#define TYPES_DLG_MOVEDLG_H
+
+#include <errno.h>
+#include <fmgt.h>
+#include <ui/entry.h>
+#include <ui/label.h>
+#include <ui/pbutton.h>
+#include <ui/window.h>
+#include <stdbool.h>
+
+/** Move dialog */
+typedef struct move_dlg {
+	/** Dialog window */
+	ui_window_t *window;
+	/** "Move 'xxx'" */
+	ui_label_t *lmove;
+	/** File */
+	ui_entry_t *esize;
+	/** Destination text entry */
+	ui_entry_t *edest;
+	/** OK button */
+	ui_pbutton_t *bok;
+	/** Cancel button */
+	ui_pbutton_t *bcancel;
+	/** Move dialog callbacks */
+	struct move_dlg_cb *cb;
+	/** Callback argument */
+	void *arg;
+	/** File list */
+	fmgt_flist_t *flist;
+} move_dlg_t;
+
+/** Move dialog callbacks */
+typedef struct move_dlg_cb {
+	/** OK button was pressed */
+	void (*bok)(move_dlg_t *, void *);
+	/** Cancel button was pressed */
+	void (*bcancel)(move_dlg_t *, void *);
+	/** Window closure requested (e.g. via close button) */
+	void (*close)(move_dlg_t *, void *);
+} move_dlg_cb_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nav/types/menu.h
===================================================================
--- uspace/app/nav/types/menu.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/app/nav/types/menu.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -53,4 +53,6 @@
 	/** File / Copy */
 	void (*file_copy)(void *);
+	/** File / Move */
+	void (*file_move)(void *);
 	/** File / Exit */
 	void (*file_exit)(void *);
Index: uspace/app/nav/types/move.h
===================================================================
--- uspace/app/nav/types/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/app/nav/types/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup nav
+ * @{
+ */
+/**
+ * @file Navigator Move types
+ */
+
+#ifndef TYPES_MOVE_H
+#define TYPES_MOVE_H
+
+#include <fmgt.h>
+
+/** Navigator Move job */
+typedef struct {
+	/** Navigator */
+	struct navigator *navigator;
+	/** File list */
+	fmgt_flist_t *flist;
+	/** Destination */
+	char *dest;
+} navigator_move_job_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/fmgt.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/include/fmgt.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -44,4 +44,5 @@
 #include "fmgt/copy.h"
 #include "fmgt/flist.h"
+#include "fmgt/move.h"
 #include "fmgt/newfile.h"
 #include "fmgt/verify.h"
Index: uspace/lib/fmgt/include/fmgt/move.h
===================================================================
--- uspace/lib/fmgt/include/fmgt/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/lib/fmgt/include/fmgt/move.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/**
+ * @file
+ * @brief Move files and directories.
+ */
+
+#ifndef FMGT_MOVE_H
+#define FMGT_MOVE_H
+
+#include <errno.h>
+#include "types/fmgt.h"
+
+extern errno_t fmgt_move(fmgt_t *, fmgt_flist_t *, const char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/fmgt/include/types/fmgt.h
===================================================================
--- uspace/lib/fmgt/include/types/fmgt.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/include/types/fmgt.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -69,5 +69,7 @@
 	fmgt_io_open,
 	/** Create */
-	fmgt_io_create
+	fmgt_io_create,
+	/** Delete */
+	fmgt_io_delete
 } fmgt_io_op_type_t;
 
Index: uspace/lib/fmgt/meson.build
===================================================================
--- uspace/lib/fmgt/meson.build	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/meson.build	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -32,4 +32,5 @@
 	'src/fmgt.c',
 	'src/fsops.c',
+	'src/move.c',
 	'src/newfile.c',
 	'src/verify.c',
@@ -43,4 +44,5 @@
 	'test/fsops.c',
 	'test/main.c',
+	'test/move.c',
 	'test/newfile.c',
 	'test/verify.c',
Index: uspace/lib/fmgt/private/fsops.h
===================================================================
--- uspace/lib/fmgt/private/fsops.h	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/private/fsops.h	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -46,4 +46,5 @@
 errno_t fmgt_create_file(fmgt_t *, const char *, int *, fmgt_exists_action_t *);
 errno_t fmgt_create_dir(fmgt_t *, const char *);
+errno_t fmgt_remove(fmgt_t *, const char *);
 errno_t fmgt_read(fmgt_t *, int, const char *, aoff64_t *, void *, size_t,
     size_t *);
Index: uspace/lib/fmgt/src/fsops.c
===================================================================
--- uspace/lib/fmgt/src/fsops.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/src/fsops.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -166,4 +166,34 @@
 }
 
+/** Remove file or empty directory.
+ *
+ * @param fmgt File management object
+ * @param fame File or directory name
+ * @return EOK on success or an error code
+ */
+errno_t fmgt_remove(fmgt_t *fmgt, const char *fname)
+{
+	fmgt_io_error_t err;
+	fmgt_error_action_t action;
+	errno_t rc;
+
+	do {
+		rc = vfs_unlink_path(fname);
+		if (rc == EOK)
+			break;
+
+		/* I/O error */
+		err.fname = fname;
+		err.optype = fmgt_io_delete;
+		err.rc = rc;
+
+		fmgt_timer_stop(fmgt);
+		action = fmgt_io_error_query(fmgt, &err);
+		fmgt_timer_start(fmgt);
+	} while (action == fmgt_er_retry);
+
+	return rc;
+}
+
 /** Read data from file.
  *
Index: uspace/lib/fmgt/src/move.c
===================================================================
--- uspace/lib/fmgt/src/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/lib/fmgt/src/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fmgt
+ * @{
+ */
+/** @file Move files and directories.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <vfs/vfs.h>
+
+#include "fmgt.h"
+#include "fmgt/walk.h"
+#include "../private/fmgt.h"
+#include "../private/fsops.h"
+
+static errno_t fmgt_move_dir_enter(fmgt_walk_t *, const char *, const char *);
+static errno_t fmgt_move_file(fmgt_walk_t *, const char *, const char *);
+static errno_t fmgt_move_dir_leave(fmgt_walk_t *, const char *, const char *);
+
+static fmgt_walk_cb_t fmgt_move_cb = {
+	.dir_enter = fmgt_move_dir_enter,
+	.file = fmgt_move_file,
+	.dir_leave = fmgt_move_dir_leave
+};
+
+/** Move operation - enter directory.
+ *
+ * @param walk Walk
+ * @param fname Source directory name
+ * @param dest Destination directory name
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_move_dir_enter(fmgt_walk_t *walk, const char *src,
+    const char *dest)
+{
+	fmgt_t *fmgt = (fmgt_t *)walk->params->arg;
+
+	(void)dest;
+	return fmgt_create_dir(fmgt, dest);
+}
+
+/** Move single file.
+ *
+ * @param walk Walk
+ * @param fname Source file name
+ * @param dest Destination file name
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_move_file(fmgt_walk_t *walk, const char *src,
+    const char *dest)
+{
+	fmgt_t *fmgt = (fmgt_t *)walk->params->arg;
+	fmgt_exists_action_t exaction;
+	int rfd;
+	int wfd;
+	size_t nr;
+	aoff64_t rpos = 0;
+	aoff64_t wpos = 0;
+	char *buffer;
+	errno_t rc;
+
+	buffer = calloc(BUFFER_SIZE, 1);
+	if (buffer == NULL)
+		return ENOMEM;
+
+	rc = fmgt_open(fmgt, src, &rfd);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+
+	rc = fmgt_create_file(fmgt, dest, &wfd, &exaction);
+	if (rc != EOK) {
+		free(buffer);
+		vfs_put(rfd);
+
+		if (rc == EEXIST && exaction != fmgt_exr_fail) {
+			if (exaction == fmgt_exr_abort)
+				walk->stop = true;
+			return EOK;
+		}
+
+		return rc;
+	}
+
+	fmgt_progress_init_file(fmgt, src);
+
+	do {
+		rc = fmgt_read(fmgt, rfd, src, &rpos, buffer, BUFFER_SIZE,
+		    &nr);
+		if (rc != EOK)
+			goto error;
+
+		rc = fmgt_write(fmgt, wfd, dest, &wpos, buffer, nr);
+		if (rc != EOK)
+			goto error;
+
+		fmgt_progress_incr_bytes(fmgt, nr);
+
+		/* User requested abort? */
+		if (fmgt_abort_query(fmgt)) {
+			rc = EINTR;
+			goto error;
+		}
+	} while (nr > 0);
+
+	free(buffer);
+	vfs_put(rfd);
+	vfs_put(wfd);
+
+	/* Remove original file. */
+	rc = fmgt_remove(fmgt, src);
+	if (rc != EOK)
+		return rc;
+
+	fmgt_progress_incr_files(fmgt);
+	return EOK;
+error:
+	free(buffer);
+	vfs_put(rfd);
+	vfs_put(wfd);
+	fmgt_final_progress_update(fmgt);
+	return rc;
+}
+
+/** Move operation - leave directory.
+ *
+ * @param walk Walk
+ * @param fname Source directory name
+ * @param dest Destination directory name
+ * @return EOK on success or an error code
+ */
+static errno_t fmgt_move_dir_leave(fmgt_walk_t *walk, const char *src,
+    const char *dest)
+{
+	fmgt_t *fmgt = (fmgt_t *)walk->params->arg;
+
+	(void)dest;
+	return fmgt_remove(fmgt, src);
+}
+
+/** Move files.
+ *
+ * @param fmgt File management object
+ * @param flist File list
+ * @param dest Destination path
+ * @return EOK on success or an error code
+ */
+errno_t fmgt_move(fmgt_t *fmgt, fmgt_flist_t *flist, const char *dest)
+{
+	fmgt_walk_params_t params;
+	errno_t rc;
+
+	fmgt_walk_params_init(&params);
+
+	params.flist = flist;
+	params.dest = dest;
+	params.cb = &fmgt_move_cb;
+	params.arg = (void *)fmgt;
+	if (fmgt_is_dir(dest))
+		params.into_dest = true;
+
+	fmgt_progress_init(fmgt);
+
+	fmgt_timer_start(fmgt);
+	fmgt_initial_progress_update(fmgt);
+	rc = fmgt_walk(&params);
+	fmgt_final_progress_update(fmgt);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/fmgt/test/copy.c
===================================================================
--- uspace/lib/fmgt/test/copy.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/test/copy.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2025 Jiri Svoboda
+ * Copyright (c) 2026 Jiri Svoboda
  * All rights reserved.
  *
@@ -167,4 +167,5 @@
 	char *fname;
 	char *dname;
+	char *rname;
 	FILE *f;
 	char *p;
@@ -181,8 +182,11 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rv = asprintf(&fname, "%s/%s", p, "a");
-	PCUT_ASSERT_TRUE(rv >= 0);
-
-	rv = asprintf(&dname, "%s/%s", p, "b");
+	rv = asprintf(&fname, "%s/a", p);
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&dname, "%s/b", p);
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&rname, "%s/b/a", p);
 	PCUT_ASSERT_TRUE(rv >= 0);
 
@@ -208,7 +212,4 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = fmgt_flist_append(flist, dname);
-	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
-
 	rc = fmgt_copy(fmgt, flist, dname);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
@@ -217,4 +218,7 @@
 
 	rv = remove(fname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rv = remove(rname);
 	PCUT_ASSERT_INT_EQUALS(0, rv);
 
Index: uspace/lib/fmgt/test/fsops.c
===================================================================
--- uspace/lib/fmgt/test/fsops.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/test/fsops.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -131,4 +131,36 @@
 }
 
+/** Remove file. */
+PCUT_TEST(remove)
+{
+	fmgt_t *fmgt = NULL;
+	char buf[L_tmpnam];
+	FILE *f;
+	char *p;
+	int rv;
+	errno_t rc;
+
+	/* Create name for temporary file */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(p, "wb");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	rv = fprintf(f, "X");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = fclose(f);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_remove(fmgt, p);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	fmgt_destroy(fmgt);
+}
+
 /** Read data from file. */
 PCUT_TEST(read)
Index: uspace/lib/fmgt/test/main.c
===================================================================
--- uspace/lib/fmgt/test/main.c	(revision 59ed424e90d86012aab2cf8150d0ea23830de273)
+++ uspace/lib/fmgt/test/main.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -31,7 +31,9 @@
 PCUT_INIT;
 
+PCUT_IMPORT(copy);
 PCUT_IMPORT(flist);
 PCUT_IMPORT(fmgt);
 PCUT_IMPORT(fsops);
+PCUT_IMPORT(move);
 PCUT_IMPORT(newfile);
 PCUT_IMPORT(verify);
Index: uspace/lib/fmgt/test/move.c
===================================================================
--- uspace/lib/fmgt/test/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
+++ uspace/lib/fmgt/test/move.c	(revision f9c30b9a950523d4a244e2b7d0bc184c17c6d010)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2026 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <fmgt.h>
+#include <pcut/pcut.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <str.h>
+#include <vfs/vfs.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(move);
+
+/** Move file to file. */
+PCUT_TEST(move_file_file)
+{
+	fmgt_t *fmgt = NULL;
+	char buf[L_tmpnam];
+	char *sname;
+	char *dname;
+	FILE *f;
+	char *p;
+	int rv;
+	fmgt_flist_t *flist;
+	errno_t rc;
+
+	/* Create name for temporary directory */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Create temporary directory */
+	rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rv = asprintf(&sname, "%s/%s", p, "a");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&dname, "%s/%s", p, "b");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	f = fopen(sname, "wb");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	rv = fprintf(f, "X");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = fclose(f);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_create(&flist);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_append(flist, sname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_move(fmgt, flist, dname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	fmgt_flist_destroy(flist);
+
+	rv = remove(dname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rv = remove(p);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(sname);
+	free(dname);
+	fmgt_destroy(fmgt);
+}
+
+/** Move directory to directory. */
+PCUT_TEST(move_dir_dir)
+{
+	fmgt_t *fmgt = NULL;
+	char buf[L_tmpnam];
+	char *sname;
+	char *dname;
+	char *p;
+	int rv;
+	fmgt_flist_t *flist;
+	errno_t rc;
+
+	/* Create name for temporary directory */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Create temporary directory */
+	rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rv = asprintf(&sname, "%s/%s", p, "a");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&dname, "%s/%s", p, "b");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rc = vfs_link_path(sname, KIND_DIRECTORY, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_create(&flist);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_append(flist, sname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_move(fmgt, flist, dname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	fmgt_flist_destroy(flist);
+
+	rv = remove(dname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rv = remove(p);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(sname);
+	free(dname);
+	fmgt_destroy(fmgt);
+}
+
+/** Move files and directories into directory. */
+PCUT_TEST(move_into_dir)
+{
+	fmgt_t *fmgt = NULL;
+	char buf[L_tmpnam];
+	char *fname;
+	char *dname;
+	char *rname;
+	FILE *f;
+	char *p;
+	int rv;
+	fmgt_flist_t *flist;
+	errno_t rc;
+
+	/* Create name for temporary directory */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Create temporary directory */
+	rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rv = asprintf(&fname, "%s/a", p);
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&dname, "%s/b", p);
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = asprintf(&rname, "%s/b/a", p);
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	f = fopen(fname, "wb");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	rv = fprintf(f, "X");
+	PCUT_ASSERT_TRUE(rv >= 0);
+
+	rv = fclose(f);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rc = vfs_link_path(dname, KIND_DIRECTORY, NULL);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_create(&fmgt);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_create(&flist);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_flist_append(flist, fname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = fmgt_move(fmgt, flist, dname);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	fmgt_flist_destroy(flist);
+
+	rv = remove(rname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rv = remove(dname);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	rv = remove(p);
+	PCUT_ASSERT_INT_EQUALS(0, rv);
+
+	free(fname);
+	free(dname);
+	free(rname);
+	fmgt_destroy(fmgt);
+}
+
+PCUT_EXPORT(move);
