diff --git a/.changeset/dull-toys-share.md b/.changeset/dull-toys-share.md
new file mode 100644
index 00000000..ab14d441
--- /dev/null
+++ b/.changeset/dull-toys-share.md
@@ -0,0 +1,5 @@
+---
+'svelte-migrate': patch
+---
+
+chore: align dependencies with `sv`
diff --git a/.changeset/happy-singers-roll.md b/.changeset/happy-singers-roll.md
new file mode 100644
index 00000000..f76778a7
--- /dev/null
+++ b/.changeset/happy-singers-roll.md
@@ -0,0 +1,5 @@
+---
+'svelte-migrate': minor
+---
+
+feat: add ability to select migration to run
diff --git a/documentation/docs/20-commands/40-sv-migrate.md b/documentation/docs/20-commands/40-sv-migrate.md
index 4283a5e0..87e69568 100644
--- a/documentation/docs/20-commands/40-sv-migrate.md
+++ b/documentation/docs/20-commands/40-sv-migrate.md
@@ -8,6 +8,11 @@ Some migrations may annotate your codebase with tasks for completion that you ca
 
 ## Usage
 
+```bash
+npx sv migrate
+```
+
+You can also specify a migration directly via the CLI:
 ```bash
 npx sv migrate [migration]
 ```
diff --git a/packages/migrate/README.md b/packages/migrate/README.md
index 07ae73a9..ed7413bd 100644
--- a/packages/migrate/README.md
+++ b/packages/migrate/README.md
@@ -4,13 +4,13 @@ A CLI for migrating Svelte(Kit) codebases.
 
 Run it directly using:
 
-```
-npx svelte-migrate [migration]
+```bash
+npx sv migrate
 ```
 
-Or via the unified Svlete CLI with:
+You can also specify a migration directly via the CLI:
 
-```
+```bash
 npx sv migrate [migration]
 ```
 
diff --git a/packages/migrate/bin.js b/packages/migrate/bin.js
index df8d7de7..18f1ad8b 100755
--- a/packages/migrate/bin.js
+++ b/packages/migrate/bin.js
@@ -2,7 +2,8 @@
 import fs from 'node:fs';
 import process from 'node:process';
 import { fileURLToPath } from 'node:url';
-import colors from 'kleur';
+import pc from 'picocolors';
+import * as p from '@clack/prompts';
 
 const migration = process.argv[2];
 const dir = fileURLToPath(new URL('.', import.meta.url));
@@ -11,17 +12,29 @@ const migrations = fs
 	.readdirSync(`${dir}/migrations`)
 	.filter((migration) => fs.existsSync(`${dir}/migrations/${migration}/index.js`));
 
+const pkg = JSON.parse(fs.readFileSync(`${dir}/package.json`, 'utf8'));
+
+p.intro(`Welcome to the svelte-migrate CLI! ${pc.gray(`(v${pkg.version})`)}`);
+
 if (migrations.includes(migration)) {
-	const { migrate } = await import(`./migrations/${migration}/index.js`);
-	migrate();
+	await run_migration(migration);
 } else {
-	console.error(
-		colors
-			.bold()
-			.red(
-				`You must specify one of the following migrations: ${migrations.join(', ')}\n` +
-					'If you expected this to work, try re-running the command with the latest svelte-migrate version:\n' +
-					`  npx svelte-migrate@latest ${migration}`
-			)
-	);
+	if (migration) p.log.warning(pc.yellow(`Invalid migration "${migration}" provided.`));
+
+	const selectedMigration = await p.select({
+		message: 'Which migration would you like to run?',
+		options: migrations.map((x) => ({ value: x, label: x }))
+	});
+
+	if (!p.isCancel(selectedMigration)) await run_migration(selectedMigration);
+}
+
+p.outro("You're all set!");
+
+/**
+ * @param {string} migration
+ */
+async function run_migration(migration) {
+	const { migrate } = await import(`./migrations/${migration}/index.js`);
+	await migrate();
 }
diff --git a/packages/migrate/migrations/app-state/index.js b/packages/migrate/migrations/app-state/index.js
index 8ba9a326..b3775e20 100644
--- a/packages/migrate/migrations/app-state/index.js
+++ b/packages/migrate/migrations/app-state/index.js
@@ -1,10 +1,10 @@
-import colors from 'kleur';
+import pc from 'picocolors';
 import fs from 'node:fs';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import semver from 'semver';
 import glob from 'tiny-glob/sync.js';
-import { bail, check_git, update_svelte_file } from '../../utils.js';
+import { bail, check_git, migration_succeeded, update_svelte_file } from '../../utils.js';
 import { transform_svelte_code, update_pkg_json } from './migrate.js';
 
 export async function migrate() {
@@ -16,51 +16,46 @@ export async function migrate() {
 
 	const svelte_dep = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
 	if (svelte_dep && semver.validRange(svelte_dep) && semver.gtr('5.0.0', svelte_dep)) {
-		console.log(
-			colors
-				.bold()
-				.red('\nYou need to upgrade to Svelte version 5 first (`npx sv migrate svelte-5`).\n')
+		p.log.error(
+			pc.bold(pc.red('You need to upgrade to Svelte version 5 first (`npx sv migrate svelte-5`).'))
 		);
 		process.exit(1);
 	}
 
 	const kit_dep = pkg.devDependencies?.['@sveltejs/kit'] ?? pkg.dependencies?.['@sveltejs/kit'];
 	if (kit_dep && semver.validRange(kit_dep) && semver.gtr('2.0.0', kit_dep)) {
-		console.log(
-			colors
-				.bold()
-				.red('\nYou need to upgrade to SvelteKit version 2 first (`npx sv migrate sveltekit-2`).\n')
+		p.log.error(
+			pc.bold(
+				pc.red('You need to upgrade to SvelteKit version 2 first (`npx sv migrate sveltekit-2`).')
+			)
 		);
 		process.exit(1);
 	}
 
-	console.log(
-		colors
-			.bold()
-			.yellow(
-				'\nThis will update files in the current directory\n' +
-					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently.\n"
+	p.log.warning(
+		pc.bold(pc.yellow('This will update files in the current directory.')) +
+			'\n' +
+			pc.bold(
+				pc.yellow(
+					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently."
+				)
 			)
 	);
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
-	const folders = await prompts({
-		type: 'multiselect',
-		name: 'value',
+	const folders = await p.multiselect({
 		message: 'Which folders should be migrated?',
-		choices: fs
+		options: fs
 			.readdirSync('.')
 			.filter(
 				(dir) => fs.statSync(dir).isDirectory() && dir !== 'node_modules' && !dir.startsWith('.')
@@ -68,14 +63,14 @@ export async function migrate() {
 			.map((dir) => ({ title: dir, value: dir, selected: true }))
 	});
 
-	if (!folders.value?.length) {
+	if (p.isCancel(folders) || !folders?.length) {
 		process.exit(1);
 	}
 
 	update_pkg_json();
 
 	// For some reason {folders.value.join(',')} as part of the glob doesn't work and returns less files
-	const files = folders.value.flatMap(
+	const files = folders.flatMap(
 		/** @param {string} folder */ (folder) =>
 			glob(`${folder}/**`, { filesOnly: true, dot: true })
 				.map((file) => file.replace(/\\/g, '/'))
@@ -96,24 +91,15 @@ export async function migrate() {
 		);
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
-
-	console.log('\nRecommended next steps:\n');
-
-	const cyan = colors.bold().cyan;
-
-	const tasks = [
-		"install the updated dependencies ('npm i' / 'pnpm i' / etc) " + use_git &&
-			cyan('git commit -m "migration to $app/state"')
-	].filter(Boolean);
-
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
+	// TODO: use package-manager-detector here
+	const tasks = ["install the updated dependencies ('npm i' / 'pnpm i' / etc)"];
 	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
+		tasks.push(cyan('git commit -m "migration to $app/state"'));
+		tasks.push(`Run ${cyan('git diff')} to review changes.`);
 	}
+
+	migration_succeeded(tasks);
 }
diff --git a/packages/migrate/migrations/package/index.js b/packages/migrate/migrations/package/index.js
index 0e365476..05565eed 100644
--- a/packages/migrate/migrations/package/index.js
+++ b/packages/migrate/migrations/package/index.js
@@ -1,10 +1,10 @@
 import fs from 'node:fs';
-import colors from 'kleur';
+import pc from 'picocolors';
 import path from 'node:path';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import { pathToFileURL } from 'node:url';
-import { bail, check_git } from '../../utils.js';
+import { bail, check_git, migration_succeeded } from '../../utils.js';
 import { migrate_config } from './migrate_config.js';
 import { migrate_pkg } from './migrate_pkg.js';
 
@@ -16,24 +16,20 @@ export async function migrate() {
 		bail('Please re-run this script in a directory with a package.json');
 	}
 
-	console.log(
-		colors
-			.bold()
-			.yellow(
-				'\nThis will update your svelte.config.js and package.json in the current directory\n'
-			)
+	p.log.warning(
+		pc.bold(
+			pc.yellow('This will update your svelte.config.js and package.json in the current directory')
+		)
 	);
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
@@ -57,25 +53,16 @@ export async function migrate() {
 		migrate_config();
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
-	console.log('\nRecommended next steps:\n');
+	/** @type {string[]} */
+	const tasks = [];
 
-	const cyan = colors.bold().cyan;
+	if (use_git) tasks.push(cyan('git commit -m "migration to @sveltejs/package v2"'));
 
-	const tasks = [
-		use_git && cyan('git commit -m "migration to @sveltejs/package v2"'),
-		'Review the migration guide at https://github.com/sveltejs/kit/pull/8922',
-		'Read the updated docs at https://svelte.dev/docs/kit/packaging'
-	].filter(Boolean);
+	tasks.push('Review the migration guide at https://github.com/sveltejs/kit/pull/8922');
+	tasks.push('Read the updated docs at https://svelte.dev/docs/kit/packaging');
 
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
-
-	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
-	}
+	migration_succeeded;
 }
diff --git a/packages/migrate/migrations/package/migrate_config.js b/packages/migrate/migrations/package/migrate_config.js
index b401626d..5d42e227 100644
--- a/packages/migrate/migrations/package/migrate_config.js
+++ b/packages/migrate/migrations/package/migrate_config.js
@@ -1,5 +1,6 @@
+import * as p from '@clack/prompts';
 import fs from 'node:fs';
-import colors from 'kleur';
+import pc from 'picocolors';
 import MagicString from 'magic-string';
 import ts from 'typescript';
 
@@ -8,10 +9,12 @@ export function migrate_config() {
 		const content = fs.readFileSync('svelte.config.js', 'utf8');
 		fs.writeFileSync('svelte.config.js', remove_package_from_config(content));
 	} catch {
-		console.log(
-			colors
-				.bold()
-				.yellow('Could not remove package config from svelte.config.js, please remove it manually')
+		p.log.warning(
+			pc.bold(
+				pc.yellow(
+					'Could not remove package config from svelte.config.js, please remove it manually'
+				)
+			)
 		);
 	}
 }
diff --git a/packages/migrate/migrations/package/migrate_pkg.js b/packages/migrate/migrations/package/migrate_pkg.js
index 3e5f5b6a..f79a2294 100644
--- a/packages/migrate/migrations/package/migrate_pkg.js
+++ b/packages/migrate/migrations/package/migrate_pkg.js
@@ -1,6 +1,7 @@
+import * as p from '@clack/prompts';
 import fs from 'node:fs';
 import path from 'node:path';
-import colors from 'kleur';
+import pc from 'picocolors';
 import { guess_indent, posixify, walk } from '../../utils.js';
 
 /**
@@ -58,8 +59,8 @@ export function update_pkg_json(config, pkg, files) {
 
 	// See: https://pnpm.io/package_json#publishconfigdirectory
 	if (pkg.publishConfig?.directory || pkg.linkDirectory?.directory) {
-		console.log(
-			colors.yellow(
+		p.log.warning(
+			pc.yellow(
 				'Detected "publishConfig.directory" or "linkDirectory.directory" fields in your package.json. ' +
 					'This migration removes them, which may or may not be what you want. Please review closely.'
 			)
@@ -101,8 +102,8 @@ export function update_pkg_json(config, pkg, files) {
 			const key = `./${file.dest}`.replace(/\/index\.js$|(\/[^/]+)\.js$/, '$1');
 
 			if (clashes[key]) {
-				console.log(
-					colors.yellow(
+				p.log.warning(
+					pc.yellow(
 						`Duplicate "${key}" export. Closely review your "exports" field in package.json after the migration.`
 					)
 				);
@@ -169,15 +170,15 @@ export function update_pkg_json(config, pkg, files) {
 			if (svelte_export) {
 				pkg.svelte = svelte_export;
 			} else {
-				console.log(
-					colors.yellow(
+				p.log.warning(
+					pc.yellow(
 						'Cannot generate a "svelte" entry point because the "." entry in "exports" is not a string. Please specify a "svelte" entry point yourself\n'
 					)
 				);
 			}
 		} else {
-			console.log(
-				colors.yellow(
+			p.log.warning(
+				pc.yellow(
 					'Cannot generate a "svelte" entry point because the "." entry in "exports" is missing. Please specify a "svelte" entry point yourself\n'
 				)
 			);
diff --git a/packages/migrate/migrations/routes/index.js b/packages/migrate/migrations/routes/index.js
index 9f043327..fa95d446 100644
--- a/packages/migrate/migrations/routes/index.js
+++ b/packages/migrate/migrations/routes/index.js
@@ -1,8 +1,8 @@
 import fs from 'node:fs';
-import colors from 'kleur';
+import pc from 'picocolors';
 import path from 'node:path';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import glob from 'tiny-glob/sync.js';
 import { pathToFileURL } from 'node:url';
 import { migrate_scripts } from './migrate_scripts/index.js';
@@ -10,7 +10,7 @@ import { migrate_page } from './migrate_page_js/index.js';
 import { migrate_page_server } from './migrate_page_server/index.js';
 import { migrate_server } from './migrate_server/index.js';
 import { adjust_imports, task } from './utils.js';
-import { bail, relative, move_file, check_git } from '../../utils.js';
+import { bail, relative, move_file, check_git, migration_succeeded } from '../../utils.js';
 
 export async function migrate() {
 	if (!fs.existsSync('svelte.config.js')) {
@@ -56,18 +56,16 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().yellow('\nThis will overwrite files in the current directory!\n'));
+	p.log.warning(pc.bold(pc.yellow('This will overwrite files in the current directory!')));
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
@@ -185,27 +183,17 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
-
-	console.log('\nRecommended next steps:\n');
-
-	const cyan = colors.bold().cyan;
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
 	const tasks = [
 		use_git && cyan('git commit -m "svelte-migrate: renamed files"'),
 		'Review the migration guide at https://github.com/sveltejs/kit/discussions/5774',
 		`Search codebase for ${cyan('"@migration"')} and manually complete migration tasks`,
 		use_git && cyan('git add -A'),
-		use_git && cyan('git commit -m "svelte-migrate: updated files"')
+		use_git && cyan('git commit -m "svelte-migrate: updated files"'),
+		use_git && `Run ${cyan('git diff')} to review changes.`
 	].filter(Boolean);
 
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
-
-	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
-	}
+	migration_succeeded(tasks);
 }
diff --git a/packages/migrate/migrations/self-closing-tags/index.js b/packages/migrate/migrations/self-closing-tags/index.js
index ced6ca30..d724f2f3 100644
--- a/packages/migrate/migrations/self-closing-tags/index.js
+++ b/packages/migrate/migrations/self-closing-tags/index.js
@@ -1,33 +1,32 @@
-import colors from 'kleur';
+import pc from 'picocolors';
 import fs from 'node:fs';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import glob from 'tiny-glob/sync.js';
 import { remove_self_closing_tags } from './migrate.js';
 import { pathToFileURL } from 'node:url';
 import { resolve } from 'import-meta-resolve';
+import { migration_succeeded } from '../../utils.js';
 
 export async function migrate() {
 	let compiler;
 	try {
 		compiler = await import_from_cwd('svelte/compiler');
 	} catch {
-		console.log(colors.bold().red('❌ Could not find a local Svelte installation.'));
+		p.log.error(pc.bold(pc.red('❌ Could not find a local Svelte installation.')));
 		return;
 	}
 
-	console.log(
-		colors.bold().yellow('\nThis will update .svelte files inside the current directory\n')
+	p.log.warning(
+		pc.bold(pc.yellow('\nThis will update .svelte files inside the current directory\n'))
 	);
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
@@ -44,8 +43,9 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().green('✔ Your project has been updated'));
-	console.log('  If using Prettier, please upgrade to the latest prettier-plugin-svelte version');
+	const tasks = ['If using Prettier, please upgrade to the latest prettier-plugin-svelte version'];
+
+	migration_succeeded(tasks);
 }
 
 /** @param {string} name */
diff --git a/packages/migrate/migrations/svelte-4/index.js b/packages/migrate/migrations/svelte-4/index.js
index 4fea5173..4bab4316 100644
--- a/packages/migrate/migrations/svelte-4/index.js
+++ b/packages/migrate/migrations/svelte-4/index.js
@@ -1,9 +1,15 @@
-import colors from 'kleur';
+import pc from 'picocolors';
 import fs from 'node:fs';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import glob from 'tiny-glob/sync.js';
-import { bail, check_git, update_js_file, update_svelte_file } from '../../utils.js';
+import {
+	bail,
+	check_git,
+	migration_succeeded,
+	update_js_file,
+	update_svelte_file
+} from '../../utils.js';
 import { transform_code, transform_svelte_code, update_pkg_json } from './migrate.js';
 
 export async function migrate() {
@@ -11,33 +17,30 @@ export async function migrate() {
 		bail('Please re-run this script in a directory with a package.json');
 	}
 
-	console.log(
-		colors
-			.bold()
-			.yellow(
-				'\nThis will update files in the current directory\n' +
-					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently.\n"
+	p.log.warning(
+		pc.bold(pc.yellow('This will update files in the current directory.')) +
+			'\n' +
+			pc.bold(
+				pc.yellow(
+					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently."
+				)
 			)
 	);
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
-	const folders = await prompts({
-		type: 'multiselect',
-		name: 'value',
+	const folders = await p.multiselect({
 		message: 'Which folders should be migrated?',
-		choices: fs
+		options: fs
 			.readdirSync('.')
 			.filter(
 				(dir) => fs.statSync(dir).isDirectory() && dir !== 'node_modules' && !dir.startsWith('.')
@@ -45,18 +48,20 @@ export async function migrate() {
 			.map((dir) => ({ title: dir, value: dir, selected: true }))
 	});
 
-	if (!folders.value?.length) {
+	if (p.isCancel(folders) || !folders?.length) {
 		process.exit(1);
 	}
 
-	const migrate_transition = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const migrate_transition = await p.confirm({
 		message:
 			'Add the `|global` modifier to currently global transitions for backwards compatibility? More info at https://svelte.dev/docs/svelte/v4-migration-guide#transitions-are-local-by-default',
-		initial: true
+		initialValue: true
 	});
 
+	if (p.isCancel(migrate_transition)) {
+		process.exit(1);
+	}
+
 	update_pkg_json();
 
 	// const { default: config } = fs.existsSync('svelte.config.js')
@@ -68,8 +73,8 @@ export async function migrate() {
 		'.svelte'
 	];
 	const extensions = [...svelte_extensions, '.ts', '.js'];
-	// For some reason {folders.value.join(',')} as part of the glob doesn't work and returns less files
-	const files = folders.value.flatMap(
+	// For some reason {folders.join(',')} as part of the glob doesn't work and returns less files
+	const files = folders.flatMap(
 		/** @param {string} folder */ (folder) =>
 			glob(`${folder}/**`, { filesOnly: true, dot: true })
 				.map((file) => file.replace(/\\/g, '/'))
@@ -80,7 +85,7 @@ export async function migrate() {
 		if (extensions.some((ext) => file.endsWith(ext))) {
 			if (svelte_extensions.some((ext) => file.endsWith(ext))) {
 				update_svelte_file(file, transform_code, (code) =>
-					transform_svelte_code(code, migrate_transition.value)
+					transform_svelte_code(code, migrate_transition)
 				);
 			} else {
 				update_js_file(file, transform_code);
@@ -88,25 +93,15 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
-
-	console.log('\nRecommended next steps:\n');
-
-	const cyan = colors.bold().cyan;
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
 	const tasks = [
 		use_git && cyan('git commit -m "migration to Svelte 4"'),
 		'Review the migration guide at https://svelte.dev/docs/svelte/v4-migration-guide',
-		'Read the updated docs at https://svelte.dev/docs/svelte'
+		'Read the updated docs at https://svelte.dev/docs/svelte',
+		use_git && `Run ${cyan('git diff')} to review changes.`
 	].filter(Boolean);
 
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
-
-	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
-	}
+	migration_succeeded(tasks);
 }
diff --git a/packages/migrate/migrations/svelte-5/index.js b/packages/migrate/migrations/svelte-5/index.js
index 7ba620f1..92a1dfa9 100644
--- a/packages/migrate/migrations/svelte-5/index.js
+++ b/packages/migrate/migrations/svelte-5/index.js
@@ -1,14 +1,20 @@
 import { resolve } from 'import-meta-resolve';
-import colors from 'kleur';
+import pc from 'picocolors';
 import { execSync } from 'node:child_process';
 import process from 'node:process';
 import fs from 'node:fs';
 import { dirname } from 'node:path';
 import { fileURLToPath, pathToFileURL } from 'node:url';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import semver from 'semver';
 import glob from 'tiny-glob/sync.js';
-import { bail, check_git, update_js_file, update_svelte_file } from '../../utils.js';
+import {
+	bail,
+	check_git,
+	migration_succeeded,
+	update_js_file,
+	update_svelte_file
+} from '../../utils.js';
 import { migrate as migrate_svelte_4 } from '../svelte-4/index.js';
 import { migrate as migrate_sveltekit_2 } from '../sveltekit-2/index.js';
 import { transform_module_code, transform_svelte_code, update_pkg_json } from './migrate.js';
@@ -22,29 +28,27 @@ export async function migrate() {
 
 	const svelte_dep = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
 	if (svelte_dep && semver.validRange(svelte_dep) && semver.gtr('4.0.0', svelte_dep)) {
-		console.log(
-			colors
-				.bold()
-				.yellow(
-					'\nDetected Svelte 3. You need to upgrade to Svelte version 4 first (`npx sv migrate svelte-4`).\n'
+		p.log.warning(
+			pc.bold(
+				pc.yellow(
+					'Detected Svelte 3. You need to upgrade to Svelte version 4 first (`npx sv migrate svelte-4`).'
 				)
+			)
 		);
-		const response = await prompts({
-			type: 'confirm',
-			name: 'value',
+		const response = await p.confirm({
 			message: 'Run svelte-4 migration now?',
-			initial: false
+			initialValue: false
 		});
-		if (!response.value) {
+		if (p.isCancel(response) || !response) {
 			process.exit(1);
 		} else {
 			await migrate_svelte_4();
-			console.log(
-				colors
-					.bold()
-					.green(
-						'svelte-4 migration complete. Check that everything is ok, then run `npx sv migrate svelte-5` again to continue the Svelte 5 migration.\n'
+			p.log.success(
+				pc.bold(
+					pc.green(
+						'svelte-4 migration complete. Check that everything is ok, then run `npx sv migrate svelte-5` again to continue the Svelte 5 migration.'
 					)
+				)
 			);
 			process.exit(0);
 		}
@@ -52,29 +56,27 @@ export async function migrate() {
 
 	const kit_dep = pkg.devDependencies?.['@sveltejs/kit'] ?? pkg.dependencies?.['@sveltejs/kit'];
 	if (kit_dep && semver.validRange(kit_dep) && semver.gtr('2.0.0', kit_dep)) {
-		console.log(
-			colors
-				.bold()
-				.yellow(
-					'\nDetected SvelteKit 1. You need to upgrade to SvelteKit version 2 first (`npx sv migrate sveltekit-2`).\n'
+		p.log.warning(
+			pc.bold(
+				pc.yellow(
+					'Detected SvelteKit 1. You need to upgrade to SvelteKit version 2 first (`npx sv migrate sveltekit-2`).'
 				)
+			)
 		);
-		const response = await prompts({
-			type: 'confirm',
-			name: 'value',
+		const response = await p.confirm({
 			message: 'Run sveltekit-2 migration now?',
-			initial: false
+			initialValue: false
 		});
-		if (!response.value) {
+		if (p.isCancel(response) || !response) {
 			process.exit(1);
 		} else {
 			await migrate_sveltekit_2();
-			console.log(
-				colors
-					.bold()
-					.green(
-						'sveltekit-2 migration complete. Check that everything is ok, then run `npx sv migrate svelte-5` again to continue the Svelte 5 migration.\n'
+			p.log.success(
+				pc.bold(
+					pc.green(
+						'sveltekit-2 migration complete. Check that everything is ok, then run `npx sv migrate svelte-5` again to continue the Svelte 5 migration.'
 					)
+				)
 			);
 			process.exit(0);
 		}
@@ -95,83 +97,80 @@ export async function migrate() {
 		}
 	} catch (e) {
 		console.log(e);
-		console.log(
-			colors
-				.bold()
-				.red(
+		p.log.error(
+			pc.bold(
+				pc.red(
 					'❌ Could not install Svelte. Manually bump the dependency to version 5 in your package.json, install it, then try again.'
 				)
+			)
 		);
 		return;
 	}
 
-	console.log(
-		colors
-			.bold()
-			.yellow(
-				'\nThis will update files in the current directory\n' +
-					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently.\n"
+	p.log.warning(
+		pc.bold(pc.yellow('This will update files in the current directory.')) +
+			'\n' +
+			pc.bold(
+				pc.yellow(
+					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently."
+				)
 			)
 	);
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
-	const folders = await prompts({
-		type: 'multiselect',
-		name: 'value',
+	const dirs = fs
+		.readdirSync('.')
+		.filter(
+			(dir) => fs.statSync(dir).isDirectory() && dir !== 'node_modules' && !dir.startsWith('.')
+		);
+
+	let folders = await p.multiselect({
 		message: 'Which folders should be migrated?',
-		choices: fs
-			.readdirSync('.')
-			.filter(
-				(dir) => fs.statSync(dir).isDirectory() && dir !== 'node_modules' && !dir.startsWith('.')
-			)
-			.map((dir) => ({ title: dir, value: dir, selected: true }))
+		options: dirs
+			.map((dir) => ({ label: dir, value: dir }))
 			.concat([
 				{
-					title: 'custom (overrides selection, allows to specify sub folders)',
-					value: ',', // a value that definitely isn't a valid folder name so it cannot clash
-					selected: false
+					label: 'custom (overrides selection, allows to specify sub folders)',
+					value: ',' // a value that definitely isn't a valid folder name so it cannot clash
 				}
-			])
+			]),
+		initialValues: dirs
 	});
 
-	if (!folders.value?.length) {
+	if (p.isCancel(folders) || !folders?.length) {
 		process.exit(1);
 	}
 
-	if (folders.value.includes(',')) {
-		const custom = await prompts({
-			type: 'list',
-			name: 'value',
+	if (folders.includes(',')) {
+		const custom = await p.text({
 			message: 'Specify folder paths (comma separated)'
 		});
 
-		if (!custom.value) {
+		if (p.isCancel(custom) || !custom) {
 			process.exit(1);
 		}
 
-		folders.value = custom.value.map((/** @type {string} */ folder) => (folder = folder.trim()));
+		folders = custom.split(',').map((/** @type {string} */ folder) => (folder = folder.trim()));
 	}
 
-	const do_migration = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const do_migration = await p.confirm({
 		message:
 			'Do you want to use the migration tool to convert your Svelte components to the new syntax? (You can also do this per component or sub path later)',
-		initial: true
+		initialValue: true
 	});
 
+	if (p.isCancel(do_migration)) process.exit(1);
+
 	update_pkg_json();
 
 	const use_ts = fs.existsSync('tsconfig.json');
@@ -186,7 +185,7 @@ export async function migrate() {
 	];
 	const extensions = [...svelte_extensions, '.ts', '.js'];
 	// For some reason {folders.value.join(',')} as part of the glob doesn't work and returns less files
-	const files = folders.value.flatMap(
+	const files = folders.flatMap(
 		/** @param {string} folder */ (folder) =>
 			glob(`${folder}/**`, { filesOnly: true, dot: true })
 				.map((file) => file.replace(/\\/g, '/'))
@@ -196,7 +195,7 @@ export async function migrate() {
 	for (const file of files) {
 		if (extensions.some((ext) => file.endsWith(ext))) {
 			if (svelte_extensions.some((ext) => file.endsWith(ext))) {
-				if (do_migration.value) {
+				if (do_migration) {
 					update_svelte_file(file, transform_module_code, (code) =>
 						transform_svelte_code(code, migrate, { filename: file, use_ts })
 					);
@@ -207,28 +206,18 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
-
-	console.log('\nRecommended next steps:\n');
-
-	const cyan = colors.bold().cyan;
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
 	const tasks = [
 		"install the updated dependencies ('npm i' / 'pnpm i' / etc) " +
 			'(note that there may be peer dependency issues when not all your libraries officially support Svelte 5 yet. In this case try installing with the --force option)',
 		use_git && cyan('git commit -m "migration to Svelte 5"'),
-		'Review the migration guide at https://svelte.dev/docs/svelte/v5-migration-guide'
+		'Review the migration guide at https://svelte.dev/docs/svelte/v5-migration-guide',
+		`Run ${cyan('git diff')} to review changes.`
 	].filter(Boolean);
 
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
-
-	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
-	}
+	migration_succeeded(tasks);
 }
 
 /** @param {string} name */
diff --git a/packages/migrate/migrations/sveltekit-2/index.js b/packages/migrate/migrations/sveltekit-2/index.js
index c62442ab..466233d3 100644
--- a/packages/migrate/migrations/sveltekit-2/index.js
+++ b/packages/migrate/migrations/sveltekit-2/index.js
@@ -1,12 +1,13 @@
-import colors from 'kleur';
+import pc from 'picocolors';
 import fs from 'node:fs';
 import process from 'node:process';
-import prompts from 'prompts';
+import * as p from '@clack/prompts';
 import semver from 'semver';
 import glob from 'tiny-glob/sync.js';
 import {
 	bail,
 	check_git,
+	migration_succeeded,
 	update_js_file,
 	update_svelte_file,
 	update_tsconfig
@@ -28,25 +29,24 @@ export async function migrate() {
 		bail('Please re-run this script in a directory with a svelte.config.js');
 	}
 
-	console.log(
-		colors
-			.bold()
-			.yellow(
-				'\nThis will update files in the current directory\n' +
-					"If you're inside a monorepo, run this in individual project directories rather than the workspace root.\n"
+	p.log.warning(
+		pc.bold(pc.yellow('This will update files in the current directory.')) +
+			'\n' +
+			pc.bold(
+				pc.yellow(
+					"If you're inside a monorepo, don't run this in the root directory, rather run it in all projects independently."
+				)
 			)
 	);
 
 	const use_git = check_git();
 
-	const response = await prompts({
-		type: 'confirm',
-		name: 'value',
+	const response = await p.confirm({
 		message: 'Continue?',
-		initial: false
+		initialValue: false
 	});
 
-	if (!response.value) {
+	if (p.isCancel(response) || !response) {
 		process.exit(1);
 	}
 
@@ -57,45 +57,37 @@ export async function migrate() {
 	}
 
 	if (semver.validRange(svelte_dep) && semver.gtr('4.0.0', svelte_dep)) {
-		console.log(
-			colors
-				.bold()
-				.yellow(
-					'\nSvelteKit 2 requires Svelte 4 or newer. We recommend running the `svelte-4` migration first (`npx sv migrate svelte-4`).\n'
+		p.log.warning(
+			pc.bold(
+				pc.yellow(
+					'SvelteKit 2 requires Svelte 4 or newer. We recommend running the `svelte-4` migration first (`npx sv migrate svelte-4`).'
 				)
+			)
 		);
-		const response = await prompts({
-			type: 'confirm',
-			name: 'value',
+		const response = await p.confirm({
 			message: 'Run `svelte-4` migration now?',
-			initial: false
+			initialValue: false
 		});
-		if (!response.value) {
+		if (p.isCancel(response) || !response) {
 			process.exit(1);
 		} else {
 			await migrate_svelte_4();
-			console.log(
-				colors
-					.bold()
-					.green('`svelte-4` migration complete. Continue with `sveltekit-2` migration?\n')
+			p.log.success(
+				pc.bold(pc.green('`svelte-4` migration complete. Continue with `sveltekit-2` migration?\n'))
 			);
-			const response = await prompts({
-				type: 'confirm',
-				name: 'value',
+			const response = await p.confirm({
 				message: 'Continue?',
-				initial: false
+				initialValue: false
 			});
-			if (!response.value) {
+			if (p.isCancel(response) || !response) {
 				process.exit(1);
 			}
 		}
 	}
 
-	const folders = await prompts({
-		type: 'multiselect',
-		name: 'value',
+	const folders = await p.multiselect({
 		message: 'Which folders should be migrated?',
-		choices: fs
+		options: fs
 			.readdirSync('.')
 			.filter(
 				(dir) =>
@@ -107,7 +99,7 @@ export async function migrate() {
 			.map((dir) => ({ title: dir, value: dir, selected: dir === 'src' }))
 	});
 
-	if (!folders.value?.length) {
+	if (p.isCancel(folders) || !folders?.length) {
 		process.exit(1);
 	}
 
@@ -124,8 +116,8 @@ export async function migrate() {
 		'.svelte'
 	];
 	const extensions = [...svelte_extensions, '.ts', '.js'];
-	// For some reason {folders.value.join(',')} as part of the glob doesn't work and returns less files
-	const files = folders.value.flatMap(
+	// For some reason {folders.join(',')} as part of the glob doesn't work and returns less files
+	const files = folders.flatMap(
 		/** @param {string} folder */ (folder) =>
 			glob(`${folder}/**`, { filesOnly: true, dot: true })
 				.map((file) => file.replace(/\\/g, '/'))
@@ -142,26 +134,16 @@ export async function migrate() {
 		}
 	}
 
-	console.log(colors.bold().green('✔ Your project has been migrated'));
-
-	console.log('\nRecommended next steps:\n');
-
-	const cyan = colors.bold().cyan;
+	/** @type {(s: string) => string} */
+	const cyan = (s) => pc.bold(pc.cyan(s));
 
 	const tasks = [
 		'Run npm install (or the corresponding installation command of your package manager)',
 		use_git && cyan('git commit -m "migration to SvelteKit 2"'),
 		'Review the migration guide at https://svelte.dev/docs/kit/migrating-to-sveltekit-2',
-		'Read the updated docs at https://svelte.dev/docs/kit'
+		'Read the updated docs at https://svelte.dev/docs/kit',
+		use_git && `Run ${cyan('git diff')} to review changes.`
 	].filter(Boolean);
 
-	tasks.forEach((task, i) => {
-		console.log(`  ${i + 1}: ${task}`);
-	});
-
-	console.log('');
-
-	if (use_git) {
-		console.log(`Run ${cyan('git diff')} to review changes.\n`);
-	}
+	migration_succeeded(tasks);
 }
diff --git a/packages/migrate/package.json b/packages/migrate/package.json
index 92111c99..4a1b65ad 100644
--- a/packages/migrate/package.json
+++ b/packages/migrate/package.json
@@ -27,10 +27,10 @@
 		"svelte-migrate": "./bin.js"
 	},
 	"dependencies": {
+		"@clack/prompts": "^0.9.0",
 		"import-meta-resolve": "^4.1.0",
-		"kleur": "^4.1.5",
 		"magic-string": "^0.30.15",
-		"prompts": "^2.4.2",
+		"picocolors": "^1.1.1",
 		"semver": "^7.6.3",
 		"tiny-glob": "^0.2.9",
 		"ts-morph": "^24.0.0",
diff --git a/packages/migrate/utils.js b/packages/migrate/utils.js
index 944461f0..4fd00665 100644
--- a/packages/migrate/utils.js
+++ b/packages/migrate/utils.js
@@ -1,4 +1,5 @@
-import colors from 'kleur';
+import * as p from '@clack/prompts';
+import pc from 'picocolors';
 import MagicString from 'magic-string';
 import { execFileSync, execSync } from 'node:child_process';
 import fs from 'node:fs';
@@ -9,7 +10,7 @@ import ts from 'typescript';
 
 /** @param {string} message */
 export function bail(message) {
-	console.error(colors.bold().red(message));
+	p.log.error(pc.bold(pc.red(message)));
 	process.exit(1);
 }
 
@@ -152,15 +153,15 @@ export function check_git() {
 
 			if (status) {
 				const message =
-					'Your git working directory is dirty — we recommend committing your changes before running this migration.\n';
-				console.log(colors.bold().red(message));
+					'Your git working directory is dirty — we recommend committing your changes before running this migration.';
+				p.log.warning(pc.bold(pc.red(message)));
 			}
 		} catch {
 			// would be weird to have a .git folder if git is not installed,
 			// but always expect the unexpected
 			const message =
-				'Could not detect a git installation. If this is unexpected, please raise an issue: https://github.com/sveltejs/kit.\n';
-			console.log(colors.bold().red(message));
+				'Could not detect a git installation. If this is unexpected, please raise an issue: https://github.com/sveltejs/cli.\n';
+			p.log.warning(pc.bold(pc.red(message)));
 			use_git = false;
 		}
 	}
@@ -419,3 +420,25 @@ export function add_named_import(source, _import, method) {
 		});
 	}
 }
+
+/**
+ * @param {(string | false)[]} next_steps
+ */
+export function migration_succeeded(next_steps) {
+	p.log.success(pc.bold(pc.green('✔ Your project has been migrated')));
+
+	if (!next_steps || next_steps.length === 0) {
+		return;
+	}
+
+	/** @type {string[]} */
+	const messages = [];
+
+	next_steps.forEach((step, i) => {
+		if (!step) return;
+
+		messages.push(`${i + 1}: ${step}`);
+	});
+
+	p.note(messages.join('\n'), 'Recommended next steps:');
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ff7592a3..fa68d69c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -256,18 +256,18 @@ importers:
 
   packages/migrate:
     dependencies:
+      '@clack/prompts':
+        specifier: ^0.9.0
+        version: 0.9.0
       import-meta-resolve:
         specifier: ^4.1.0
         version: 4.1.0
-      kleur:
-        specifier: ^4.1.5
-        version: 4.1.5
       magic-string:
         specifier: ^0.30.15
         version: 0.30.15
-      prompts:
-        specifier: ^2.4.2
-        version: 2.4.2
+      picocolors:
+        specifier: ^1.1.1
+        version: 1.1.1
       semver:
         specifier: ^7.6.3
         version: 7.6.3
@@ -382,6 +382,12 @@ packages:
   '@changesets/write@0.3.2':
     resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==}
 
+  '@clack/core@0.4.0':
+    resolution: {integrity: sha512-YJCYBsyJfNDaTbvDUVSJ3SgSuPrcujarRgkJ5NLjexDZKvaOiVVJvAQYx8lIgG0qRT8ff0fPgqyBCVivanIZ+A==}
+
+  '@clack/prompts@0.9.0':
+    resolution: {integrity: sha512-nGsytiExgUr4FL0pR/LeqxA28nz3E0cW7eLTSh3Iod9TGrbBt8Y7BHbV3mmkNC4G0evdYyQ3ZsbiBkk7ektArA==}
+
   '@esbuild/aix-ppc64@0.21.5':
     resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
     engines: {node: '>=12'}
@@ -1752,10 +1758,6 @@ packages:
     resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
     engines: {node: '>=6'}
 
-  kleur@4.1.5:
-    resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
-    engines: {node: '>=6'}
-
   known-css-properties@0.35.0:
     resolution: {integrity: sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==}
 
@@ -2038,10 +2040,6 @@ packages:
     engines: {node: '>=14'}
     hasBin: true
 
-  prompts@2.4.2:
-    resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
-    engines: {node: '>= 6'}
-
   ps-tree@1.2.0:
     resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
     engines: {node: '>= 0.10'}
@@ -2668,6 +2666,17 @@ snapshots:
       human-id: 1.0.2
       prettier: 2.8.8
 
+  '@clack/core@0.4.0':
+    dependencies:
+      picocolors: 1.1.1
+      sisteransi: 1.0.5
+
+  '@clack/prompts@0.9.0':
+    dependencies:
+      '@clack/core': 0.4.0
+      picocolors: 1.1.1
+      sisteransi: 1.0.5
+
   '@esbuild/aix-ppc64@0.21.5':
     optional: true
 
@@ -3921,8 +3930,6 @@ snapshots:
 
   kleur@3.0.3: {}
 
-  kleur@4.1.5: {}
-
   known-css-properties@0.35.0: {}
 
   levn@0.4.1:
@@ -4156,11 +4163,6 @@ snapshots:
 
   prettier@3.4.2: {}
 
-  prompts@2.4.2:
-    dependencies:
-      kleur: 3.0.3
-      sisteransi: 1.0.5
-
   ps-tree@1.2.0:
     dependencies:
       event-stream: 3.3.4