diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index cc28c050a6bc3be151648b81fbbc722b197d2b81..75c86931c7e45a0251bf764ef56b994b899db8c3 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1847,19 +1847,55 @@
  */
 #if EXTRUDERS > 1
   // Z raise distance for tool-change, as needed for some extruders
-  #define TOOLCHANGE_ZRAISE     2  // (mm)
-  //#define TOOLCHANGE_NO_RETURN   // Never return to the previous position on tool-change
+  #define TOOLCHANGE_ZRAISE                 2 // (mm)
+  //#define TOOLCHANGE_ZRAISE_BEFORE_RETRACT  // Apply raise before swap retraction (if enabled)
+  //#define TOOLCHANGE_NO_RETURN              // Never return to previous position on tool-change
   #if ENABLED(TOOLCHANGE_NO_RETURN)
-    //#define EVENT_GCODE_AFTER_TOOLCHANGE "G12X"   // G-code to run after tool-change is complete
+    //#define EVENT_GCODE_AFTER_TOOLCHANGE "G12X"   // Extra G-code to run after tool-change
   #endif
 
-  // Retract and prime filament on tool-change
+  /**
+   * Retract and prime filament on tool-change to reduce
+   * ooze and stringing and to get cleaner transitions.
+   */
   //#define TOOLCHANGE_FILAMENT_SWAP
   #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-    #define TOOLCHANGE_FIL_SWAP_LENGTH          12  // (mm)
-    #define TOOLCHANGE_FIL_EXTRA_PRIME           2  // (mm)
-    #define TOOLCHANGE_FIL_SWAP_RETRACT_SPEED 3600  // (mm/m)
-    #define TOOLCHANGE_FIL_SWAP_PRIME_SPEED   3600  // (mm/m)
+    // Load / Unload
+    #define TOOLCHANGE_FS_LENGTH              12  // (mm) Load / Unload length
+    #define TOOLCHANGE_FS_EXTRA_RESUME_LENGTH  0  // (mm) Extra length for better restart, fine tune by LCD/Gcode)
+    #define TOOLCHANGE_FS_RETRACT_SPEED   (50*60) // (mm/m) (Unloading)
+    #define TOOLCHANGE_FS_UNRETRACT_SPEED (25*60) // (mm/m) (On SINGLENOZZLE or Bowden loading must be slowed down)
+
+    // Longer prime to clean out a SINGLENOZZLE
+    #define TOOLCHANGE_FS_EXTRA_PRIME          0  // (mm) Extra priming length
+    #define TOOLCHANGE_FS_PRIME_SPEED    (4.6*60) // (mm/m) Extra priming feedrate
+    #define TOOLCHANGE_FS_WIPE_RETRACT         0  // (mm/m) Retract before cooling for less stringing, better wipe, etc.
+
+    // Cool after prime to reduce stringing
+    #define TOOLCHANGE_FS_FAN                 -1  // Fan index or -1 to skip
+    #define TOOLCHANGE_FS_FAN_SPEED          255  // 0-255
+    #define TOOLCHANGE_FS_FAN_TIME            10  // (seconds)
+
+    // Swap uninitialized extruder with TOOLCHANGE_FS_PRIME_SPEED for all lengths (recover + prime)
+    // (May break filament if not retracted beforehand.)
+    //#define TOOLCHANGE_FS_INIT_BEFORE_SWAP
+
+    // Prime on the first T command even if the same or no toolchange / swap
+    // Enable it (M217 V[0/1]) before printing, to avoid unwanted priming on host connect
+    //#define TOOLCHANGE_FS_PRIME_FIRST_USED
+
+    /**
+     * Tool Change Migration
+     * This feature provides G-code and LCD options to switch tools mid-print.
+     * All applicable tool properties are migrated so the print can continue.
+     * Tools must be closely matching and other restrictions may apply.
+     * Useful to:
+     *   - Change filament color without interruption
+     *   - Switch spools automatically on filament runout
+     *   - Switch to a different nozzle on an extruder jam
+     */
+    #define TOOLCHANGE_MIGRATION_FEATURE
+
   #endif
 
   /**
@@ -1870,8 +1906,10 @@
   #if ENABLED(TOOLCHANGE_PARK)
     #define TOOLCHANGE_PARK_XY    { X_MIN_POS + 10, Y_MIN_POS + 10 }
     #define TOOLCHANGE_PARK_XY_FEEDRATE 6000  // (mm/m)
+    //#define TOOLCHANGE_PARK_X_ONLY          // X axis only move
+    //#define TOOLCHANGE_PARK_Y_ONLY          // Y axis only move
   #endif
-#endif
+#endif // EXTRUDERS > 1
 
 /**
  * Advanced Pause
diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp
index f74e0c741b9bbc5602d247b9885f82927571bafe..bba4f4b1fa85196efe1b52b16c1e80a8a987a067 100644
--- a/Marlin/src/feature/runout.cpp
+++ b/Marlin/src/feature/runout.cpp
@@ -39,6 +39,10 @@ bool FilamentMonitorBase::enabled = true,
   bool FilamentMonitorBase::host_handling; // = false
 #endif
 
+#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+  #include "../module/tool_change.h"
+#endif
+
 /**
  * Called by FilamentSensorSwitch::run when filament is detected.
  * Called by FilamentSensorEncoder::block_completed when motion is detected.
@@ -76,6 +80,11 @@ void event_filament_runout() {
 
   if (TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print)) return;  // Action already in progress. Purge triggered repeated runout.
 
+  #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+    if (migration.in_progress) return;  // Action already in progress. Purge triggered repeated runout.
+    if (migration.automode) { extruder_migration(); return; }
+  #endif
+
   TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getActiveTool()));
 
   #if EITHER(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS)
diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp
index 44e69c429843b0de078276df61fdf256d9b75b80..6e8c899fb019a92b26a64089eddd1bd66d5574f7 100644
--- a/Marlin/src/gcode/config/M217.cpp
+++ b/Marlin/src/gcode/config/M217.cpp
@@ -27,6 +27,10 @@
 #include "../gcode.h"
 #include "../../module/tool_change.h"
 
+#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+  #include "../../module/motion.h"
+#endif
+
 #include "../../MarlinCore.h" // for SP_X_STR, etc.
 
 extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[];
@@ -35,16 +39,30 @@ void M217_report(const bool eeprom=false) {
 
   #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
     serialprintPGM(eeprom ? PSTR("  M217") : PSTR("Toolchange:"));
-    SERIAL_ECHOPAIR(" S", LINEAR_UNIT(toolchange_settings.swap_length));
-    SERIAL_ECHOPAIR_P(SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime));
-    SERIAL_ECHOPAIR_P(SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed));
-    SERIAL_ECHOPAIR(" R", LINEAR_UNIT(toolchange_settings.retract_speed));
+    SERIAL_ECHOPAIR(" S", LINEAR_UNIT(toolchange_settings.swap_length),
+                    " B", LINEAR_UNIT(toolchange_settings.extra_resume));
+    SERIAL_ECHOPAIR_P(SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime),
+                      SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed));
+    SERIAL_ECHOPAIR(" R", LINEAR_UNIT(toolchange_settings.retract_speed),
+                    " U", LINEAR_UNIT(toolchange_settings.unretract_speed),
+                    " F", toolchange_settings.fan_speed,
+                    " G", toolchange_settings.fan_time);
+
+    #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+      SERIAL_ECHOPAIR(" N", int(migration.automode));
+      SERIAL_ECHOPAIR(" L", LINEAR_UNIT(migration.last));
+    #endif
 
     #if ENABLED(TOOLCHANGE_PARK)
+      SERIAL_ECHOPAIR(" W", LINEAR_UNIT(toolchange_settings.enable_park));
       SERIAL_ECHOPAIR_P(SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x));
       SERIAL_ECHOPAIR_P(SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y));
     #endif
 
+    #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
+      SERIAL_ECHOPAIR(" V", LINEAR_UNIT(enable_first_prime));
+    #endif
+
   #else
 
     UNUSED(eeprom);
@@ -58,48 +76,98 @@ void M217_report(const bool eeprom=false) {
 /**
  * M217 - Set SINGLENOZZLE toolchange parameters
  *
+ *  // Tool change command
+ *  Q           Prime active tool and exit
+ *
+ *  // Tool change settings
  *  S[linear]   Swap length
- *  E[linear]   Purge length
+ *  B[linear]   Extra Swap length
+ *  E[linear]   Prime length
  *  P[linear/m] Prime speed
  *  R[linear/m] Retract speed
+ *  U[linear/m] UnRetract speed
+ *  V[linear]   0/1 Enable auto prime first extruder used
+ *  W[linear]   0/1 Enable park & Z Raise
  *  X[linear]   Park X (Requires TOOLCHANGE_PARK)
  *  Y[linear]   Park Y (Requires TOOLCHANGE_PARK)
  *  Z[linear]   Z Raise
+ *  F[linear]   Fan Speed 0-255
+ *  G[linear/s] Fan time
+ *
+ * Tool migration settings
+ *  A[0|1]      Enable auto-migration on runout
+ *  L[index]    Last extruder to use for auto-migration
+ *
+ * Tool migration command
+ *  T[index]    Migrate to next extruder or the given extruder
  */
 void GcodeSuite::M217() {
 
-  #define SPR_PARAM
-  #define XY_PARAM
-
   #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
 
-    #undef SPR_PARAM
-    #define SPR_PARAM "SPRE"
+    static constexpr float max_extrude = TERN(PREVENT_LENGTHY_EXTRUDE, EXTRUDE_MAXLENGTH, 500);
 
-    static constexpr float max_extrude =
-      #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
-        EXTRUDE_MAXLENGTH
-      #else
-        500
-      #endif
-    ;
+    if (parser.seen('Q')) { tool_change_prime(); return; }
 
     if (parser.seenval('S')) { const float v = parser.value_linear_units(); toolchange_settings.swap_length = constrain(v, 0, max_extrude); }
+    if (parser.seenval('B')) { const float v = parser.value_linear_units(); toolchange_settings.extra_resume = constrain(v, -10, 10); }
     if (parser.seenval('E')) { const float v = parser.value_linear_units(); toolchange_settings.extra_prime = constrain(v, 0, max_extrude); }
     if (parser.seenval('P')) { const int16_t v = parser.value_linear_units(); toolchange_settings.prime_speed = constrain(v, 10, 5400); }
     if (parser.seenval('R')) { const int16_t v = parser.value_linear_units(); toolchange_settings.retract_speed = constrain(v, 10, 5400); }
+    if (parser.seenval('U')) { const int16_t v = parser.value_linear_units(); toolchange_settings.unretract_speed = constrain(v, 10, 5400); }
+    #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0
+      if (parser.seenval('F')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_speed = constrain(v, 0, 255); }
+      if (parser.seenval('G')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_time = constrain(v, 1, 30); }
+    #endif
+  #endif
+
+  #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
+    if (parser.seenval('V')) { enable_first_prime = parser.value_linear_units(); }
   #endif
 
   #if ENABLED(TOOLCHANGE_PARK)
-    #undef XY_PARAM
-    #define XY_PARAM "XY"
-    if (parser.seenval('X')) { toolchange_settings.change_point.x = parser.value_linear_units(); }
-    if (parser.seenval('Y')) { toolchange_settings.change_point.y = parser.value_linear_units(); }
+    if (parser.seenval('W')) { toolchange_settings.enable_park = parser.value_linear_units(); }
+    if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); }
+    if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); }
   #endif
 
   if (parser.seenval('Z')) { toolchange_settings.z_raise = parser.value_linear_units(); }
 
-  if (!parser.seen(SPR_PARAM XY_PARAM "Z")) M217_report();
+  #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+    migration.target = 0;       // 0 = disabled
+
+    if (parser.seenval('L')) {  // Last
+      const int16_t lval = parser.value_int();
+      if (WITHIN(lval, 0, EXTRUDERS - 1)) {
+        migration.last = lval;
+        migration.automode = (active_extruder < migration.last);
+      }
+    }
+
+    if (parser.seen('A'))       // Auto on/off
+      migration.automode = parser.value_bool();
+
+    if (parser.seen('T')) {     // Migrate now
+      if (parser.has_value()) {
+        const int16_t tval = parser.value_int();
+        if (WITHIN(tval, 0, EXTRUDERS - 1) && tval != active_extruder) {
+          migration.target = tval + 1;
+          extruder_migration();
+          migration.target = 0; // disable
+          return;
+        }
+        else
+          migration.target = 0; // disable
+      }
+      else {
+        extruder_migration();
+        return;
+      }
+    }
+
+  #endif
+
+  M217_report();
 }
 
 #endif // EXTRUDERS > 1
diff --git a/Marlin/src/gcode/config/M221.cpp b/Marlin/src/gcode/config/M221.cpp
index 8522b544fc8badb1ee7e987a0511caf131f76b57..7f170e012bbcdf2c79591f6b74351bd99061207b 100644
--- a/Marlin/src/gcode/config/M221.cpp
+++ b/Marlin/src/gcode/config/M221.cpp
@@ -33,10 +33,8 @@ void GcodeSuite::M221() {
   const int8_t target_extruder = get_target_extruder_from_command();
   if (target_extruder < 0) return;
 
-  if (parser.seenval('S')) {
-    planner.flow_percentage[target_extruder] = parser.value_int();
-    planner.refresh_e_factor(target_extruder);
-  }
+  if (parser.seenval('S'))
+    planner.set_flow(target_extruder, parser.value_int());
   else {
     SERIAL_ECHO_START();
     SERIAL_CHAR('E', '0' + target_extruder);
diff --git a/Marlin/src/gcode/sd/M1001.cpp b/Marlin/src/gcode/sd/M1001.cpp
index e5082be31fe60841a6c091b52729b3c365853a63..8f1427a9abaef346317cbb22abb2a1bdfd559ae4 100644
--- a/Marlin/src/gcode/sd/M1001.cpp
+++ b/Marlin/src/gcode/sd/M1001.cpp
@@ -31,10 +31,6 @@
   #include "../queue.h"
 #endif
 
-#if HAS_LEDS_OFF_FLAG
-  #include "../../MarlinCore.h"
-#endif
-
 #if EITHER(LCD_SET_PROGRESS_MANUALLY, SD_REPRINT_LAST_SELECTED_FILE)
   #include "../../lcd/ultralcd.h"
 #endif
@@ -44,6 +40,7 @@
 #endif
 
 #if HAS_LEDS_OFF_FLAG
+  #include "../../MarlinCore.h" // for wait_for_user_response
   #include "../../feature/leds/printer_event_leds.h"
 #endif
 
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index bb42c39665dfc566fc1a2192c10858020960f805..9269c76b7d31427ae8a84ba70169ff5d8125b75c 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -2222,8 +2222,8 @@
   #define FILAMENT_CHANGE_SLOW_LOAD_LENGTH 0
 #endif
 
-#if EXTRUDERS > 1 && !defined(TOOLCHANGE_FIL_EXTRA_PRIME)
-  #define TOOLCHANGE_FIL_EXTRA_PRIME 0
+#if EXTRUDERS > 1 && !defined(TOOLCHANGE_FS_EXTRA_PRIME)
+  #define TOOLCHANGE_FS_EXTRA_PRIME 0
 #endif
 
 /**
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 6a0d0bd8e67b86a95495234692fb4c000ae182cb..d1024e44cee164f822c9991dd5d09708663fce71 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -833,14 +833,15 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
   #endif
 
   #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-    #ifndef TOOLCHANGE_FIL_SWAP_LENGTH
-      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_LENGTH. Please update your Configuration."
-    #elif !defined(TOOLCHANGE_FIL_SWAP_RETRACT_SPEED)
-      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_RETRACT_SPEED. Please update your Configuration."
-    #elif !defined(TOOLCHANGE_FIL_SWAP_PRIME_SPEED)
-      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_PRIME_SPEED. Please update your Configuration."
+    #ifndef TOOLCHANGE_FS_LENGTH
+      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_LENGTH. Please update your Configuration_adv.h."
+    #elif !defined(TOOLCHANGE_FS_RETRACT_SPEED)
+      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_RETRACT_SPEED. Please update your Configuration_adv.h."
+    #elif !defined(TOOLCHANGE_FS_PRIME_SPEED)
+      #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_PRIME_SPEED. Please update your Configuration_adv.h."
     #endif
   #endif
+
   #if ENABLED(TOOLCHANGE_PARK)
     #ifndef TOOLCHANGE_PARK_XY
       #error "TOOLCHANGE_PARK requires TOOLCHANGE_PARK_XY. Please update your Configuration."
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp
index 8bbbb231e20078a1de59b955b72c41a5a6c05917..91acd0a3607f6498d272caec157fa506af940a9c 100644
--- a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp
@@ -573,8 +573,7 @@ void DGUSScreenVariableHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, voi
       #endif
     }
 
-    planner.flow_percentage[target_extruder] = newvalue;
-    planner.refresh_e_factor(target_extruder);
+    planner.set_flow(target_extruder, newvalue);
     ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
   #else
     UNUSED(var); UNUSED(val_ptr);
diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp
index b272d9d496974ffe1ca0dfc3e30972142fb73784..dd5ddd3b668468cf8c6f129b830a7692bacb82c4 100644
--- a/Marlin/src/lcd/extui/ui_api.cpp
+++ b/Marlin/src/lcd/extui/ui_api.cpp
@@ -669,10 +669,7 @@ namespace ExtUI {
   float getRetractAcceleration_mm_s2()                { return planner.settings.retract_acceleration; }
   float getTravelAcceleration_mm_s2()                 { return planner.settings.travel_acceleration; }
   void setFeedrate_mm_s(const feedRate_t fr)          { feedrate_mm_s = fr; }
-  void setFlow_percent(const int16_t flow, const extruder_t extr) {
-    planner.flow_percentage[extr] = flow;
-    planner.refresh_e_factor(extr);
-  }
+  void setFlow_percent(const int16_t flow, const extruder_t extr) { planner.set_flow(extr, flow); }
   void setMinFeedrate_mm_s(const feedRate_t fr)       { planner.settings.min_feedrate_mm_s = fr; }
   void setMinTravelFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_travel_feedrate_mm_s = fr; }
   void setPrintingAcceleration_mm_s2(const float acc) { planner.settings.acceleration = acc; }
diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h
index c8f0e6b13b1410a35dea5c1a068f12ff12d21591..3e852249886f460e69c8d31e31ff2f76bbac92dd 100644
--- a/Marlin/src/lcd/language/language_cz.h
+++ b/Marlin/src/lcd/language/language_cz.h
@@ -357,8 +357,8 @@ namespace Language_cz {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Délka zavedení");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Výměna nástroje");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Zdvih Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Rychlost primár.");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Rychlost retrak.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Rychlost primár.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Rychlost retrak.");
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Tryska standby");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Vyměnit filament");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Vyměnit filament *");
diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h
index 4d0516e8d6936e46628a6a2a5df5369475e3197f..211869fc9c6a2386f92d2e74f8c242c6394068b6 100644
--- a/Marlin/src/lcd/language/language_de.h
+++ b/Marlin/src/lcd/language/language_de.h
@@ -347,9 +347,9 @@ namespace Language_de {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Entladelänge");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Werkzeugwechsel");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Z anheben");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Prime-Geschwin.");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Einzug-Geschwin.");
-
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Prime-Geschwin.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Einzug-Geschwin.");
+  PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Düsen-Standby");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Filament wechseln");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Filament wechseln *");
   PROGMEM Language_Str MSG_FILAMENTLOAD                    = _UxGT("Filament laden");
diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h
index a3e25d9145d4fabbd2a7b165a1629388de9586b2..94d9d44cf78c7aa7806f67d6c790189791706fbe 100644
--- a/Marlin/src/lcd/language/language_en.h
+++ b/Marlin/src/lcd/language/language_en.h
@@ -371,11 +371,22 @@ namespace Language_en {
   PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVER_SWAPF   = _UxGT("S UnRet V");
   PROGMEM Language_Str MSG_AUTORETRACT                     = _UxGT("AutoRetr.");
   PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH            = _UxGT("Swap Length");
+  PROGMEM Language_Str MSG_FILAMENT_SWAP_EXTRA             = _UxGT("Swap Extra");
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Purge Length");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Tool Change");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Z Raise");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Prime Speed");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Retract Speed");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Prime Speed");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Retract Speed");
+  PROGMEM Language_Str MSG_FILAMENT_PARK_ENABLED           = _UxGT("Park Head");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_UNRETRACT_SPEED    = _UxGT("Recover Speed");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_SPEED          = _UxGT("Fan Speed");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_TIME           = _UxGT("Fan Time");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_ON               = _UxGT("Auto ON");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_OFF              = _UxGT("Auto OFF");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION                  = _UxGT("Tool Migration");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_AUTO             = _UxGT("Auto-migration");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_END              = _UxGT("Last Extruder");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_SWAP             = _UxGT("Migrate to *");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Change Filament");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Change Filament *");
   PROGMEM Language_Str MSG_FILAMENTLOAD                    = _UxGT("Load Filament");
diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h
index 015663e885a9705f3fe239a2384b2dada2f50be5..c95fd09f101300d88e7ad6e6886169836379e8c5 100644
--- a/Marlin/src/lcd/language/language_es.h
+++ b/Marlin/src/lcd/language/language_es.h
@@ -367,8 +367,8 @@ namespace Language_es {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Purgar longitud");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Cambiar Herramienta");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Aumentar Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Vel. de Cebado");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Vel. de retracción");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Vel. de Cebado");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Vel. de retracción");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Cambiar filamento");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Cambiar filamento *");
   PROGMEM Language_Str MSG_FILAMENTLOAD                    = _UxGT("Cargar filamento");
diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h
index 2fca6adbb40ff6b6f68d29a6158fe8d5401c513e..23258b9015e8f3b67c6ce6bac37c078f83f13ad0 100644
--- a/Marlin/src/lcd/language/language_fr.h
+++ b/Marlin/src/lcd/language/language_fr.h
@@ -53,7 +53,7 @@ namespace Language_fr {
   PROGMEM Language_Str MSG_MAIN                            = _UxGT("Menu principal");
   PROGMEM Language_Str MSG_ADVANCED_SETTINGS               = _UxGT("Config. avancée");
   PROGMEM Language_Str MSG_CONFIGURATION                   = _UxGT("Configuration");
-  PROGMEM Language_Str MSG_AUTOSTART                       = _UxGT("Exéc. auto#.gcode");
+  PROGMEM Language_Str MSG_AUTOSTART                       = _UxGT("Exéc. auto.gcode");
   PROGMEM Language_Str MSG_DISABLE_STEPPERS                = _UxGT("Arrêter moteurs");
   PROGMEM Language_Str MSG_DEBUG_MENU                      = _UxGT("Menu debug");
   PROGMEM Language_Str MSG_PROGRESS_BAR_TEST               = _UxGT("Test barre progress.");
@@ -329,10 +329,21 @@ namespace Language_fr {
   PROGMEM Language_Str MSG_AUTORETRACT                     = _UxGT("Rétraction auto");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Changement outil");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Augmenter Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Vitesse primaire");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Vitesse rétract°");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Vitesse primaire");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Vitesse rétract°");
+  PROGMEM Language_Str MSG_FILAMENT_PARK_ENABLED           = _UxGT("Garer Extrudeur");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_UNRETRACT_SPEED    = _UxGT("Vitesse reprise");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_SPEED          = _UxGT("Vit.  ventil.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_TIME           = _UxGT("Temps ventil.");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_ON               = _UxGT("Auto ON");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_OFF              = _UxGT("Auto OFF");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION                  = _UxGT("Migration d'outil");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_AUTO             = _UxGT("Migration auto");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_END              = _UxGT("Extrudeur Final");
+  PROGMEM Language_Str MSG_TOOL_MIGRATION_SWAP             = _UxGT("Migrer vers *");
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Attente buse");
   PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH            = _UxGT("Longueur retrait");
+  PROGMEM Language_Str MSG_FILAMENT_SWAP_EXTRA             = _UxGT("Longueur Extra");
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Longueur de purge");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Changer filament");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Changer filament *");
diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h
index fa9f371971601b2b7e34d50aa64f3be577954051..d747b781834090b907f5d30be4818309cc5934a4 100644
--- a/Marlin/src/lcd/language/language_gl.h
+++ b/Marlin/src/lcd/language/language_gl.h
@@ -371,8 +371,8 @@ namespace Language_gl {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Lonxitude de Purga");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Cambiar Ferramenta");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Levantar Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Velocidade prim.");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Vel. de Retracción");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Velocidade prim.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Vel. de Retracción");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Cambiar Filamento");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Cambiar Filamento *");
   PROGMEM Language_Str MSG_FILAMENTLOAD                    = _UxGT("Cargar Filamento");
diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h
index d17c100490714c5719cf164954d53365c27a1a18..20af26be07d4b77ad9a76fba381fa74c73384f51 100644
--- a/Marlin/src/lcd/language/language_it.h
+++ b/Marlin/src/lcd/language/language_it.h
@@ -370,8 +370,8 @@ namespace Language_it {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Lunghezza spurgo");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Cambio utensile");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Risalita Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Velocità innesco");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Velocità retrazione");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Velocità innesco");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Velocità retrazione");
   PROGMEM Language_Str MSG_NOZZLE_PARKED                   = _UxGT("Ugello Parcheggiato");
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Standby ugello");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Cambia filamento");
diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h
index 0cb4f25499e2991e878e57a7da4f0879f77b3af2..4fb2df6eec640f98a97da8da57cc54b8e2b1b091 100644
--- a/Marlin/src/lcd/language/language_pl.h
+++ b/Marlin/src/lcd/language/language_pl.h
@@ -339,8 +339,8 @@ namespace Language_pl {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Długość oczyszczania");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Zmiana narzędzia");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Podniesienie Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Prędkość napełniania");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Prędkość wycofania");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Prędkość napełniania");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Prędkość wycofania");
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Dysza w oczekiwaniu");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Zmień filament");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Zmień filament *");
diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h
index 469b75e82321b2260def39a4fd0916b98a03f934..0d355147f8132577aeccbff9316e426caddab799 100644
--- a/Marlin/src/lcd/language/language_pt_br.h
+++ b/Marlin/src/lcd/language/language_pt_br.h
@@ -286,8 +286,8 @@ namespace Language_pt_br {
   PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH            = _UxGT("Distancia Retração");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Mudar Ferramenta");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Levantar Z");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Preparar Veloc.");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Veloc. Retração");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Preparar Veloc.");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Veloc. Retração");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Trocar Filamento");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Trocar Filamento *");
   PROGMEM Language_Str MSG_FILAMENTLOAD_E                  = _UxGT("Carregar Filamento *");
diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h
index a33b0d315dc274ec768f7d10f09e74509a0e565b..aa68ece9921026507d80497f12db036424f379c5 100644
--- a/Marlin/src/lcd/language/language_tr.h
+++ b/Marlin/src/lcd/language/language_tr.h
@@ -365,8 +365,8 @@ namespace Language_tr {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("Tasfiye uzunluğu");
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Takım Değişimi");
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Z Yükselt");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Birincil Hız");
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Geri Çekme Hızı");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Birincil Hız");
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Geri Çekme Hızı");
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("Nozul Beklemede");
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Filaman Değiştir");
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Filaman Değiştir *");
diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h
index 781a1242b8e7e5db3172d0546eeba74a0127c827..8538c81831b5b5a741ca187a7870159e0145f3f1 100644
--- a/Marlin/src/lcd/language/language_vi.h
+++ b/Marlin/src/lcd/language/language_vi.h
@@ -299,8 +299,8 @@ namespace Language_vi {
   PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH            = _UxGT("Khoảng Cách Rút");                      // Retract Distance
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("Thay Đổi Công Cụ");                     // Tool Change
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Đưa Lên Z");                            // Z Raise
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("Tốc Độ Tuôn Ra");                       // Prime Speed
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("Tốc Độ Rút Lại");                       // Retract Speed
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("Tốc Độ Tuôn Ra");                       // Prime Speed
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("Tốc Độ Rút Lại");                       // Retract Speed
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("Thay dây nhựa");                        // change filament
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("Thay dây nhựa *");                      // change filament
   PROGMEM Language_Str MSG_FILAMENTLOAD                    = _UxGT("Nạp dây nhựa");                         // load filament
diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h
index 6bb7d759f6da2762895e1ada58d3110e99e3ddc5..1019fcb03ac876ebc948cb99eb40d4c380ccac20 100644
--- a/Marlin/src/lcd/language/language_zh_TW.h
+++ b/Marlin/src/lcd/language/language_zh_TW.h
@@ -346,8 +346,8 @@ namespace Language_zh_TW {
   PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH           = _UxGT("清除長度");   //"Purge Length"
   PROGMEM Language_Str MSG_TOOL_CHANGE                     = _UxGT("交換工具"); //"Tool Change"
   PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT               = _UxGT("Z軸提昇");    //"Z Raise"
-  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD          = _UxGT("最高速度");    //"Prime Speed"
-  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD        = _UxGT("收回速度");  //"Retract Speed"
+  PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED        = _UxGT("最高速度");    //"Prime Speed"
+  PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED      = _UxGT("收回速度");  //"Retract Speed"
   PROGMEM Language_Str MSG_NOZZLE_STANDBY                  = _UxGT("噴嘴待機"); //"Nozzle Standby"
   PROGMEM Language_Str MSG_FILAMENTCHANGE                  = _UxGT("更換絲料");     //"Change filament"
   PROGMEM Language_Str MSG_FILAMENTCHANGE_E                = _UxGT("更換絲料 *");
diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp
index b0202198b7c5f21a8aa80a1df25f4c57d07bbc4a..bf7be4dbc27b58d36c66cf4822b1fb97565b905b 100644
--- a/Marlin/src/lcd/menu/menu_configuration.cpp
+++ b/Marlin/src/lcd/menu/menu_configuration.cpp
@@ -104,22 +104,50 @@ void menu_advanced_settings();
     START_MENU();
     BACK_ITEM(MSG_CONFIGURATION);
     #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-      static constexpr float max_extrude =
-        #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
-          EXTRUDE_MAXLENGTH
-        #else
-          500
-        #endif
-      ;
+      static constexpr float max_extrude = TERN(PREVENT_LENGTHY_EXTRUDE, EXTRUDE_MAXLENGTH, 500);
+      #if ENABLED(TOOLCHANGE_PARK)
+        EDIT_ITEM(bool, MSG_FILAMENT_PARK_ENABLED, &toolchange_settings.enable_park);
+      #endif
       EDIT_ITEM(float3, MSG_FILAMENT_SWAP_LENGTH, &toolchange_settings.swap_length, 0, max_extrude);
+      EDIT_ITEM(float41sign, MSG_FILAMENT_SWAP_EXTRA, &toolchange_settings.extra_resume, -10, 10);
+      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_RETRACT_SPEED, &toolchange_settings.retract_speed, 10, 5400);
+      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_UNRETRACT_SPEED, &toolchange_settings.unretract_speed, 10, 5400);
       EDIT_ITEM(float3, MSG_FILAMENT_PURGE_LENGTH, &toolchange_settings.extra_prime, 0, max_extrude);
-      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_RETRACT_SPD, &toolchange_settings.retract_speed, 10, 5400);
-      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_PRIME_SPD, &toolchange_settings.prime_speed, 10, 5400);
+      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_PRIME_SPEED, &toolchange_settings.prime_speed, 10, 5400);
+      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_FAN_SPEED, &toolchange_settings.fan_speed, 0, 255);
+      EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_FAN_TIME, &toolchange_settings.fan_time, 1, 30);
     #endif
     EDIT_ITEM(float3, MSG_TOOL_CHANGE_ZLIFT, &toolchange_settings.z_raise, 0, 10);
     END_MENU();
   }
 
+  #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+
+    #include "../../module/motion.h" // for active_extruder
+
+    void menu_toolchange_migration() {
+      START_MENU();
+      BACK_ITEM(MSG_CONFIGURATION);
+
+      // Auto mode ON/OFF
+      EDIT_ITEM(bool, MSG_TOOL_MIGRATION_AUTO, &migration.automode);
+      EDIT_ITEM(uint8, MSG_TOOL_MIGRATION_END, &migration.last, 0, EXTRUDERS - 1);
+
+      // Migrate to a chosen extruder
+      PGM_P const msg_migrate = GET_TEXT(MSG_TOOL_MIGRATION_SWAP);
+      LOOP_L_N(s, EXTRUDERS) {
+        if (s != active_extruder) {
+          ACTION_ITEM_N_P(s, msg_migrate, []{
+            char cmd[12];
+            sprintf_P(cmd, PSTR("M217 T%i"), int(MenuItemBase::itemIndex));
+            queue.inject(cmd);
+          });
+        }
+      }
+      END_MENU();
+    }
+  #endif
+
 #endif
 
 #if HAS_HOTEND_OFFSET
@@ -373,6 +401,9 @@ void menu_configuration() {
   //
   #if EXTRUDERS > 1
     SUBMENU(MSG_TOOL_CHANGE, menu_tool_change);
+    #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+      SUBMENU(MSG_TOOL_MIGRATION, menu_toolchange_migration);
+    #endif
   #endif
 
   //
diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp
index 698447a4be7ce8221497705563cb285d3a49e5b5..84b8c753705c02dfbf1b2284ef2dca49eb2b67d6 100644
--- a/Marlin/src/module/configuration_store.cpp
+++ b/Marlin/src/module/configuration_store.cpp
@@ -2423,16 +2423,32 @@ void MarlinSettings::reset() {
 
   #if EXTRUDERS > 1
     #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-      toolchange_settings.swap_length = TOOLCHANGE_FIL_SWAP_LENGTH;
-      toolchange_settings.extra_prime = TOOLCHANGE_FIL_EXTRA_PRIME;
-      toolchange_settings.prime_speed = TOOLCHANGE_FIL_SWAP_PRIME_SPEED;
-      toolchange_settings.retract_speed = TOOLCHANGE_FIL_SWAP_RETRACT_SPEED;
+      toolchange_settings.swap_length     = TOOLCHANGE_FS_LENGTH;
+      toolchange_settings.extra_resume    = TOOLCHANGE_FS_EXTRA_RESUME_LENGTH;
+      toolchange_settings.retract_speed   = TOOLCHANGE_FS_RETRACT_SPEED;
+      toolchange_settings.unretract_speed = TOOLCHANGE_FS_UNRETRACT_SPEED;
+      toolchange_settings.extra_prime     = TOOLCHANGE_FS_EXTRA_PRIME;
+      toolchange_settings.prime_speed     = TOOLCHANGE_FS_PRIME_SPEED;
+      toolchange_settings.fan_speed       = TOOLCHANGE_FS_FAN_SPEED;
+      toolchange_settings.fan_time        = TOOLCHANGE_FS_FAN_TIME;
     #endif
+
+    #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
+      enable_first_prime = false;
+    #endif
+
     #if ENABLED(TOOLCHANGE_PARK)
       constexpr xyz_pos_t tpxy = TOOLCHANGE_PARK_XY;
+      toolchange_settings.enable_park = true;
       toolchange_settings.change_point = tpxy;
     #endif
+
     toolchange_settings.z_raise = TOOLCHANGE_ZRAISE;
+
+    #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+      migration = migration_defaults;
+    #endif
+
   #endif
 
   #if ENABLED(BACKLASH_GCODE)
diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h
index 7ac7d5ade7a0320ccbf930bcc28257443fc888e3..87a6e7c0a82510e0b0bcf2fb5881f1a8c47f3fc5 100644
--- a/Marlin/src/module/planner.h
+++ b/Marlin/src/module/planner.h
@@ -423,12 +423,14 @@ class Planner {
 
     #if EXTRUDERS
       FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
-        e_factor[e] = (flow_percentage[e] * 0.01f
-          #if DISABLED(NO_VOLUMETRICS)
-            * volumetric_multiplier[e]
-          #endif
-        );
+        e_factor[e] = flow_percentage[e] * 0.01f * TERN(NO_VOLUMETRICS, 1.0f, volumetric_multiplier[e]);
       }
+
+      static inline void set_flow(const uint8_t e, const int16_t flow) {
+        flow_percentage[e] = flow;
+        refresh_e_factor(e);
+      }
+
     #endif
 
     // Manage fans, paste pressure, etc.
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 23925d630cf061646791435cf630918d6bcd16e0..210d220e7b89bb57454e9f893703dd8fe67bca40 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -38,6 +38,15 @@
   toolchange_settings_t toolchange_settings;  // Initialized by settings.load()
 #endif
 
+#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+  migration_settings_t migration = migration_defaults;
+  bool enable_first_prime;
+#endif
+
+#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
+  bool toolchange_extruder_ready[EXTRUDERS];
+#endif
+
 #if ENABLED(SINGLENOZZLE)
   uint16_t singlenozzle_temp[EXTRUDERS];
   #if FAN_COUNT > 0
@@ -85,6 +94,14 @@
   #include "../feature/pause.h"
 #endif
 
+#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
+  #include "../gcode/gcode.h"
+  #if TOOLCHANGE_FS_WIPE_RETRACT <= 0
+    #undef TOOLCHANGE_FS_WIPE_RETRACT
+    #define TOOLCHANGE_FS_WIPE_RETRACT 0
+  #endif
+#endif
+
 #if DO_SWITCH_EXTRUDER
 
   #if EXTRUDERS > 3
@@ -759,6 +776,77 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a
 
 #endif // DUAL_X_CARRIAGE
 
+/**
+ * Prime active tool using TOOLCHANGE_FILAMENT_SWAP settings
+ */
+#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
+
+void tool_change_prime() {
+  if (toolchange_settings.extra_prime > 0
+    && TERN(PREVENT_COLD_EXTRUSION, !thermalManager.targetTooColdToExtrude(active_extruder), 1)
+  ) {
+    destination = current_position; // Remember the old position
+
+    const bool ok = TERN1(TOOLCHANGE_PARK, all_axes_homed() && toolchange_settings.enable_park);
+
+    // Z raise
+    if (ok) {
+      // Do a small lift to avoid the workpiece in the move back (below)
+      current_position.z += toolchange_settings.z_raise;
+      #if HAS_SOFTWARE_ENDSTOPS
+        NOMORE(current_position.z, soft_endstop.max.z);
+      #endif
+      fast_line_to_current(Z_AXIS);
+      planner.synchronize();
+    }
+
+    // Park
+    #if ENABLED(TOOLCHANGE_PARK)
+      if (ok) {
+        TERN(TOOLCHANGE_PARK_Y_ONLY,,current_position.x = toolchange_settings.change_point.x);
+        TERN(TOOLCHANGE_PARK_X_ONLY,,current_position.y = toolchange_settings.change_point.y);
+        planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), active_extruder);
+        planner.synchronize();
+      }
+    #endif
+
+    // Prime (All distances are added and slowed down to ensure secure priming in all circumstances)
+    unscaled_e_move(toolchange_settings.swap_length + toolchange_settings.extra_prime, MMM_TO_MMS(toolchange_settings.prime_speed));
+
+    // Cutting retraction
+    #if TOOLCHANGE_FS_WIPE_RETRACT
+      unscaled_e_move(-(TOOLCHANGE_FS_WIPE_RETRACT), MMM_TO_MMS(toolchange_settings.retract_speed));
+    #endif
+
+    // Cool down with fan
+    #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0
+      const int16_t fansp = thermalManager.fan_speed[TOOLCHANGE_FS_FAN];
+      thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
+      safe_delay(toolchange_settings.fan_time * 1000);
+      thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = fansp;
+    #endif
+
+    // Move back
+    #if ENABLED(TOOLCHANGE_PARK)
+      if (ok) {
+        #if ENABLED(TOOLCHANGE_NO_RETURN)
+          do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]);
+        #else
+          do_blocking_move_to(destination, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE));
+        #endif
+      }
+    #endif
+
+    // Cutting recover
+    unscaled_e_move(toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT, MMM_TO_MMS(toolchange_settings.unretract_speed));
+
+    planner.synchronize();
+    current_position.e = destination.e;
+    sync_plan_position_e(); // Resume at the old E position
+  }
+}
+#endif
+
 /**
  * Perform a tool-change, which may result in moving the
  * previous tool out of the way and the new tool into place.
@@ -826,39 +914,52 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
     const uint8_t old_tool = active_extruder;
     const bool can_move_away = !no_move && !idex_full_control;
 
-    #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-      const bool should_swap = can_move_away && toolchange_settings.swap_length;
-      #if ENABLED(PREVENT_COLD_EXTRUSION)
-        const bool too_cold = !DEBUGGING(DRYRUN) && (thermalManager.targetTooColdToExtrude(old_tool) || thermalManager.targetTooColdToExtrude(new_tool));
-      #else
-        constexpr bool too_cold = false;
-      #endif
-      if (should_swap) {
-        if (too_cold) {
-          SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD);
-          #if ENABLED(SINGLENOZZLE)
-            active_extruder = new_tool;
-            return;
-          #endif
-        }
-        else {
-          #if ENABLED(ADVANCED_PAUSE_FEATURE)
-            unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed));
-          #else
-            current_position.e -= toolchange_settings.swap_length / planner.e_factor[old_tool];
-            planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.retract_speed), old_tool);
-            planner.synchronize();
-          #endif
-        }
-      }
-    #endif // TOOLCHANGE_FILAMENT_SWAP
-
     #if HAS_LEVELING && DISABLED(SINGLENOZZLE)
       // Set current position to the physical position
       TEMPORARY_BED_LEVELING_STATE(false);
     #endif
 
+    // First tool priming. To prime again, reboot the machine.
+    #if BOTH(TOOLCHANGE_FILAMENT_SWAP, TOOLCHANGE_FS_PRIME_FIRST_USED)
+      static bool first_tool_is_primed = false;
+      if (new_tool == old_tool && !first_tool_is_primed && enable_first_prime) {
+        tool_change_prime();
+        first_tool_is_primed = true;
+        toolchange_extruder_ready[old_tool] = true; // Primed and initialized
+      }
+    #endif
+
     if (new_tool != old_tool) {
+      destination = current_position;
+
+      // Z raise before retraction
+      #if ENABLED(TOOLCHANGE_ZRAISE_BEFORE_RETRACT) && DISABLED(SWITCHING_NOZZLE)
+        if (can_move_away && TERN1(toolchange_settings.enable_park)) {
+          // Do a small lift to avoid the workpiece in the move back (below)
+          current_position.z += toolchange_settings.z_raise;
+          #if HAS_SOFTWARE_ENDSTOPS
+            NOMORE(current_position.z, soft_endstop.max.z);
+          #endif
+          fast_line_to_current(Z_AXIS);
+          planner.synchronize();
+        }
+      #endif
+
+      // Unload / Retract
+      #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
+        const bool should_swap = can_move_away && toolchange_settings.swap_length;
+                   too_cold = TERN0(PREVENT_COLD_EXTRUSION,
+                     !DEBUGGING(DRYRUN) && (thermalManager.targetTooColdToExtrude(old_tool) || thermalManager.targetTooColdToExtrude(new_tool))
+                   );
+        if (should_swap) {
+          if (too_cold) {
+            SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD);
+            if (ENABLED(SINGLENOZZLE)) { active_extruder = new_tool; return; }
+          }
+          else
+            unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed));
+        }
+      #endif
 
       TERN_(SWITCHING_NOZZLE_TWO_SERVOS, raise_nozzle(old_tool));
 
@@ -877,18 +978,23 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
         #endif
       #endif
 
-      destination = current_position;
-
-      #if DISABLED(SWITCHING_NOZZLE)
-        if (can_move_away) {
+      #if DISABLED(TOOLCHANGE_ZRAISE_BEFORE_RETRACT) && DISABLED(SWITCHING_NOZZLE)
+        if (can_move_away && TERN1(TOOLCHANGE_PARK, toolchange_settings.enable_park)) {
           // Do a small lift to avoid the workpiece in the move back (below)
           current_position.z += toolchange_settings.z_raise;
           #if HAS_SOFTWARE_ENDSTOPS
             NOMORE(current_position.z, soft_endstop.max.z);
           #endif
           fast_line_to_current(Z_AXIS);
-          TERN_(TOOLCHANGE_PARK, current_position = toolchange_settings.change_point);
-          planner.buffer_line(current_position, feedrate_mm_s, old_tool);
+        }
+      #endif
+
+      // Toolchange park
+      #if ENABLED(TOOLCHANGE_PARK) && DISABLED(SWITCHING_NOZZLE)
+        if (can_move_away && toolchange_settings.enable_park) {
+          TERN(TOOLCHANGE_PARK_Y_ONLY,,current_position.x = toolchange_settings.change_point.x);
+          TERN(TOOLCHANGE_PARK_X_ONLY,,current_position.y = toolchange_settings.change_point.y);
+          planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), old_tool);
           planner.synchronize();
         }
       #endif
@@ -932,9 +1038,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
         move_nozzle_servo(new_tool);
       #endif
 
-      #if DISABLED(DUAL_X_CARRIAGE)
-        active_extruder = new_tool; // Set the new active extruder
-      #endif
+      // Set the new active extruder
+      if (DISABLED(DUAL_X_CARRIAGE)) active_extruder = new_tool;
 
       // The newly-selected extruder XYZ is actually at...
       if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Offset Tool XYZ by { ", diff.x, ", ", diff.y, ", ", diff.z, " }");
@@ -951,7 +1056,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
       #endif
 
       // Return to position and lower again
-      if (safe_to_move && !no_move && IsRunning()) {
+      const bool should_move = safe_to_move && !no_move && IsRunning();
+      if (should_move) {
 
         #if ENABLED(SINGLENOZZLE)
           #if FAN_COUNT > 0
@@ -969,17 +1075,35 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 
         #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
           if (should_swap && !too_cold) {
-            #if ENABLED(ADVANCED_PAUSE_FEATURE)
-              unscaled_e_move(toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.prime_speed));
-              unscaled_e_move(toolchange_settings.extra_prime, ADVANCED_PAUSE_PURGE_FEEDRATE);
-            #else
-              current_position.e += toolchange_settings.swap_length / planner.e_factor[new_tool];
-              planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.prime_speed), new_tool);
-              current_position.e += toolchange_settings.extra_prime / planner.e_factor[new_tool];
-              planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.prime_speed * 0.2f), new_tool);
+
+            float fr = toolchange_settings.unretract_speed;
+
+            #if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
+              if (!toolchange_extruder_ready[new_tool]) {
+                toolchange_extruder_ready[new_tool] = true;
+                fr = toolchange_settings.prime_speed;       // Next move is a prime
+                unscaled_e_move(0, MMM_TO_MMS(fr));         // Init planner with 0 length move
+              }
+            #endif
+
+            // Unretract (or Prime)
+            unscaled_e_move(toolchange_settings.swap_length, MMM_TO_MMS(fr));
+
+            // Extra Prime
+            unscaled_e_move(toolchange_settings.extra_prime, MMM_TO_MMS(toolchange_settings.prime_speed));
+
+            // Cutting retraction
+            #if TOOLCHANGE_FS_WIPE_RETRACT
+              unscaled_e_move(-(TOOLCHANGE_FS_WIPE_RETRACT), MMM_TO_MMS(toolchange_settings.retract_speed));
+            #endif
+
+            // Cool down with fan
+            #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0
+              const int16_t fansp = thermalManager.fan_speed[TOOLCHANGE_FS_FAN];
+              thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
+              safe_delay(toolchange_settings.fan_time * 1000);
+              thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = fansp;
             #endif
-            planner.synchronize();
-            planner.set_e_position_mm((destination.e = current_position.e = current_position.e - (TOOLCHANGE_FIL_EXTRA_PRIME)));
           }
         #endif
 
@@ -1000,22 +1124,43 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
           #if ENABLED(TOOLCHANGE_NO_RETURN)
             // Just move back down
             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Move back Z only");
+
+            #if ENABLED(TOOLCHANGE_PARK)
+              if (toolchange_settings.enable_park)
+            #endif
             do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]);
+
           #else
             // Move back to the original (or adjusted) position
             if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination);
-            do_blocking_move_to(destination);
+
+            #if ENABLED(TOOLCHANGE_PARK)
+              if (toolchange_settings.enable_park) do_blocking_move_to_xy_z(destination, destination.z, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE));
+            #else
+              do_blocking_move_to_xy(destination);
+            #endif
+
           #endif
         }
+
         else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Move back skipped");
 
+        #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
+          if (should_swap && !too_cold) {
+            // Cutting recover
+            unscaled_e_move(toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT, MMM_TO_MMS(toolchange_settings.unretract_speed));
+            current_position.e = 0;
+            sync_plan_position_e(); // New extruder primed and set to 0
+          }
+        #endif
+
         TERN_(DUAL_X_CARRIAGE, active_extruder_parked = false);
       }
+
       #if ENABLED(SWITCHING_NOZZLE)
-        else {
-          // Move back down. (Including when the new tool is higher.)
+        // Move back down. (Including when the new tool is higher.)
+        if (!should_move)
           do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]);
-        }
       #endif
 
       TERN_(PRUSA_MMU2, mmu2.tool_change(new_tool));
@@ -1053,3 +1198,79 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 
   #endif // EXTRUDERS > 1
 }
+
+#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+
+  void extruder_migration() {
+
+    #if ENABLED(PREVENT_COLD_EXTRUSION)
+      if (thermalManager.targetTooColdToExtrude(active_extruder)) return;
+    #endif
+
+    // No auto-migration or specified target?
+    if (!migration.target && active_extruder >= migration.last) {
+      migration.automode = false;
+      return;
+    }
+
+    // Migrate to a target or the next extruder
+
+    uint8_t migration_extruder = active_extruder;
+
+    if (migration.target) {
+      // Specified target ok?
+      const int16_t t = migration.target - 1;
+      if (t != active_extruder) migration_extruder = t;
+    }
+    else if (migration.automode && migration_extruder < migration.last && migration_extruder < EXTRUDERS - 1)
+      migration_extruder++;
+
+    if (migration_extruder == active_extruder) return;
+
+    // Migration begins
+
+    migration.in_progress = true; // Prevent runout script
+    planner.synchronize();
+
+    // Remember position before migration
+    const float resume_current_e = current_position.e;
+
+    // Migrate the flow
+    planner.set_flow(migration_extruder, planner.flow_percentage[active_extruder]);
+
+    // Migrate the retracted state
+    #if ENABLED(FWRETRACT)
+      fwretract.retracted[migration_extruder] = fwretract.retracted[active_extruder];
+    #endif
+
+    // Migrate the temperature to the new hotend
+    #if HOTENDS > 1
+      thermalManager.setTargetHotend(thermalManager.degTargetHotend(active_extruder), migration_extruder);
+      #if HAS_DISPLAY
+        thermalManager.set_heating_message(0);
+      #endif
+      thermalManager.wait_for_hotend(active_extruder);
+    #endif
+
+    // Perform the tool change
+    tool_change(migration_extruder);
+
+    // Retract if previously retracted
+    #if ENABLED(FWRETRACT)
+      if (fwretract.retracted[active_extruder])
+        unscaled_e_move(-fwretract.settings.retract_length, fwretract.settings.retract_feedrate_mm_s);
+    #endif
+
+    // If no available extruder
+    if (EXTRUDERS < 2 || active_extruder >= EXTRUDERS - 2 || active_extruder == migration.last)
+      migration.automode = false;
+
+    migration.in_progress = false;
+
+    current_position.e = resume_current_e;
+
+    planner.synchronize();
+    planner.set_e_position_mm(current_position.e); // New extruder primed and ready
+  }
+
+#endif // TOOLCHANGE_MIGRATION_FEATURE
diff --git a/Marlin/src/module/tool_change.h b/Marlin/src/module/tool_change.h
index 0e915a0415eb0756cc59970bd7b7c938ce0c8fb9..534a17e9462d9c646a95a3cbfa6998439dc51c47 100644
--- a/Marlin/src/module/tool_change.h
+++ b/Marlin/src/module/tool_change.h
@@ -28,15 +28,39 @@
 
   typedef struct {
     #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
-      float swap_length, extra_prime;
-      int16_t prime_speed, retract_speed;
+      float swap_length, extra_prime, extra_resume;
+      int16_t prime_speed, retract_speed, unretract_speed, fan, fan_speed, fan_time;
+    #endif
+    #if ENABLED(TOOLCHANGE_PARK)
+      bool enable_park;
+      xy_pos_t change_point;
     #endif
-    TERN_(TOOLCHANGE_PARK, xy_pos_t change_point);
     float z_raise;
   } toolchange_settings_t;
 
   extern toolchange_settings_t toolchange_settings;
 
+  #if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
+    extern void tool_change_prime();
+  #endif
+
+  #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
+    extern bool enable_first_prime;
+  #endif
+
+  #if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
+    extern bool toolchange_extruder_ready[EXTRUDERS];
+  #endif
+
+  #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
+    typedef struct {
+      uint8_t target, last;
+      bool automode, in_progress;
+    } migration_settings_t;
+    constexpr migration_settings_t migration_defaults = { 0, 0, false, false };
+    extern migration_settings_t migration;
+    void extruder_migration();
+  #endif
 #endif
 
 #if DO_SWITCH_EXTRUDER
diff --git a/buildroot/share/tests/BIGTREE_GTR_V1_0-tests b/buildroot/share/tests/BIGTREE_GTR_V1_0-tests
index 0738a2818b4896355b3a960c6e3875856113620c..18a6a75f6f1bc6d1165b44d0121cc2b819e71875 100644
--- a/buildroot/share/tests/BIGTREE_GTR_V1_0-tests
+++ b/buildroot/share/tests/BIGTREE_GTR_V1_0-tests
@@ -33,6 +33,7 @@ opt_set TEMP_SENSOR_3 1
 opt_set TEMP_SENSOR_4 1
 opt_set TEMP_SENSOR_5 1
 opt_set NUM_Z_STEPPER_DRIVERS 3
+opt_enable TOOLCHANGE_FILAMENT_SWAP TOOLCHANGE_MIGRATION_FEATURE TOOLCHANGE_FS_INIT_BEFORE_SWAP TOOLCHANGE_FS_PRIME_FIRST_USED
 exec_test $1 $2 "BigTreeTech GTR 6 Extruders Triple Z"
 
 # clean up