TechEarl

Disable jQuery Migrate in WordPress

How to disable jQuery Migrate in WordPress: remove the jquery-migrate dependency on the front end so the compatibility shim stops loading, plus the testing step that tells you whether it is safe.

Ishan Karunaratne⏱️ 12 min readUpdated
Share thisCopied
How to disable jQuery Migrate in WordPress: a wp_default_scripts snippet that removes the jquery-migrate dependency on the front end while keeping it in the admin, with the JQMIGRATE console-warning test that confirms it is safe.

To stop jQuery Migrate loading on the front end, hook into wp_default_scripts and remove jquery-migrate from the jQuery script's dependency array. Guard it with ! is_admin() so the admin keeps the shim, because plenty of older plugin admin screens still need it:

php
add_action( 'wp_default_scripts', function ( $scripts ) {
    if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
        $scripts->registered['jquery']->deps = array_diff(
            $scripts->registered['jquery']->deps,
            array( 'jquery-migrate' )
        );
    }
} );

That is the whole fix, but it is the one cleanup on this blog where I will not let you copy-paste and walk away. Removing Migrate is only safe if nothing on the site relies on the deprecated jQuery APIs it patches, and the only way to know that is to test (the test before you remove it section below is the important part of this article). Read that before you ship the snippet.

What jQuery Migrate is and why WordPress loads it

jQuery Migrate is a small compatibility shim that ships alongside jQuery itself. Its job is to restore the behaviour of jQuery APIs that were deprecated or removed in jQuery 3.x, so that older code written against jQuery 1.x or 2.x keeps working unchanged. Things like jQuery.fn.size(), jQuery.parseJSON(), $.isFunction(), and a pile of removed event aliases are patched back in by Migrate, with a console warning prefixed JQMIGRATE each time something hits one.

WordPress registers it under the handle jquery-migrate and wires it in as a dependency of the jquery script. So whenever jQuery is enqueued, which is almost always on the front end (themes, sliders, form plugins, half the older plugin ecosystem still lean on it), Migrate comes along for the ride automatically. You do not enqueue it yourself; it is pulled in by the dependency chain.

The reason it is there at all is historical. WordPress modernised its bundled jQuery to the 3.x line across versions 5.5, 5.6, and 5.7 in 2020 and 2021, and shipped jQuery Migrate 3.x at the same time specifically to keep the enormous back catalogue of themes and plugins from breaking when the underlying jQuery jumped a major version. Migrate is the safety net that made that upgrade survivable.

A common misconception, repeated across a lot of the top-ranking pages on this topic, is that jQuery Migrate is "no longer loaded by default since WordPress 5.5." Here is what is actually true: the 5.5, 5.6, and 5.7 changes modernised the bundled jQuery to 3.x and shipped Migrate 3.x to ride along with it; they did not stop bundling Migrate or stop enqueueing it. Migrate is still bundled and auto-enqueued on the front end by default on every current 6.x install, pulled in through the same jquery dependency chain it always was.

The catch is that the safety net never came down. As of current WordPress, jQuery Migrate still loads by default on the front end. Core has signalled an intent to eventually drop it: there is a proposal to announce the intent to remove jQuery Migrate during the 7.0 cycle, but as of now there is no scheduled removal and no concrete timeline. So every default install is still shipping a backward-compat shim to every visitor, years after the migration it was meant to ease.

This also points forward, not just back. WordPress has been planning to eventually ship jQuery 4.0, which removes far more APIs than the 3.x line did, so finding and fixing Migrate-dependent code now (via the testing step below) is a forward-looking cleanup rather than just a micro-optimization.

How much does this actually save?

Honestly, a small win, and entirely conditional on it being safe to remove. I want to be straight about that before you go looking for it in a speed test.

Migrate is one extra script request and a little parse work. The minified file is small (a few KB), it sits behind WordPress's own asset versioning so it caches well, and on an HTTP/2 connection the request itself is cheap. What you reliably remove is:

  • One script request from the front-end page (jquery-migrate.min.js), on every page that loads jQuery.
  • A little main-thread parse and execution time, since Migrate patches the jQuery object at load.
  • One line in the "reduce unused JavaScript" column of a Lighthouse audit, if the code genuinely is unused.

That is the honest ceiling. It is the same class of micro-optimization as disabling the emoji polyfill: a clean item to tick off when you are chasing a perfect PageSpeed score, not the thing that makes a slow site fast. It is a touch more meaningful than trimming a head <meta> tag because it is a real request, but it sits well below the levers that move the needle. If the site is genuinely slow, your time goes to caching, image sizing, and your slowest plugins and queries. See tracking down ACF query bloat for the kind of problem that actually shows up in the numbers.

There is a secondary reason I remove it that has nothing to do with speed: a site still firing JQMIGRATE warnings is a site running code against jQuery APIs that no longer exist in modern jQuery. Disabling Migrate (after testing) is partly a forcing function to find and fix that rot before some future jQuery bump removes the shim from under you.

Put it in a plugin, not the theme

The snippet works in functions.php, but I do not keep it there. Theme code vanishes the moment you switch themes, and "why did the slider start throwing errors again?" is a miserable thing to debug months later, especially when the answer is a one-line dependency change that came back with a theme swap.

Drop this into wp-content/mu-plugins/te-disable-jquery-migrate.php instead. Must-use plugins load automatically, before regular plugins, and survive theme changes:

php
<?php
/**
 * Plugin Name: TE Disable jQuery Migrate
 * Plugin URI:  https://techearl.com/disable-jquery-migrate-wordpress
 * Description: Removes the jquery-migrate dependency on the front end so the compatibility shim stops loading for visitors, keeping it in the admin.
 * Version:     1.0.0
 * Author:      Ishan Karunaratne
 * Author URI:  https://techearl.com
 * License:     GPL-2.0-or-later
 * Text Domain: te-disable-jquery-migrate
 */

add_action( 'wp_default_scripts', function ( $scripts ) {
    // Keep Migrate in wp-admin; older plugin screens still lean on it.
    if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
        $scripts->registered['jquery']->deps = array_diff(
            $scripts->registered['jquery']->deps,
            array( 'jquery-migrate' )
        );
    }
} );

The ! is_admin() guard is doing real work, not box-ticking. The WordPress dashboard and a fair number of older plugin admin screens still call deprecated jQuery APIs, and breaking the admin is a far worse outcome than shipping one extra script to logged-in editors. Leave Migrate on for wp-admin and only strip it from the public front end, where you actually control (and can test) the code.

Note the hook: wp_default_scripts fires while WordPress is registering its bundled scripts, which is the moment the jquery script's dependency list is mutable. Trying to do this later on wp_enqueue_scripts is fighting the dependency resolver after it has already run. Editing deps at registration time is the clean way in.

If you do not write PHP, you do not have to. A dedicated "Disable jQuery Migrate" plugin, or a performance plugin toggle (Perfmatters has one, for example), does the same job from a settings screen. The mu-plugin above is just the no-dependency route: it adds nothing to install and maintain, and it is the same one-line dependency change either way. Whichever path you take, the testing step below still applies.

Test before you remove it

This is the part that matters, and the part most "speed up WordPress" posts skip entirely. Migrate exists to keep old code working. If you pull it out from under code that needs it, that code breaks, sometimes loudly (a broken slider, a form that will not submit) and sometimes silently (a feature that just stops firing). So before you keep the snippet, you confirm nothing on the site is relying on the shim.

The fastest check is the browser console. Migrate logs a JQMIGRATE deprecation warning every time something calls a patched API, even while Migrate is still loaded. So leave Migrate on, open your browser devtools, switch to the Console tab, and click through the site the way a visitor would: the home page, a post, the archive, any page with a slider, carousel, lightbox, or form. Watch for lines like this:

text
JQMIGRATE: jQuery.fn.size() is deprecated; use the .length property
JQMIGRATE: Migrate is installed, version 3.4.1

The second line ("Migrate is installed") is informational and always shows when Migrate is present; ignore it. The ones that matter are the specific is deprecated warnings. Every one of those is a piece of code that needs Migrate. If you see them, do not disable Migrate yet. Track down what is calling that API (the warning often includes a stack trace if you expand it) and either fix the code or, if it is a third-party plugin you cannot change, leave Migrate on for that site.

If you would rather not eyeball the console, the official WordPress jQuery Migrate Helper plugin does this for you: install it, browse the site, and it surfaces the deprecated calls it caught, so you can see exactly what (if anything) is still leaning on the shim. It is the tool the core team built precisely for this decision. Run it, get a clean report across the pages a visitor actually touches, then disable Migrate.

Only when you have walked the site and seen no JQMIGRATE deprecation warnings (or a clean Migrate Helper report) is it safe to keep the snippet. Skipping this step is how you end up with a subtly broken front end and no idea why.

Verify it worked

Once you have tested and shipped the plugin, confirm Migrate is actually gone from the front end. Logged out, in a private window, grep the page source:

text
$ curl -s https://example.com/ | grep -i jquery-migrate
(no output)

No output means the dependency was removed cleanly and the script is no longer enqueued. For contrast, check the admin still has it (log in and view a dashboard page source): jquery-migrate.min.js should still be there, which is the guard doing its job.

Then load the public site one more time with the console open and click around. You want two things to be true at once: no jquery-migrate request in the Network tab, and no JavaScript errors in the console. If the script is still loading after deploying, the usual causes are a page cache serving stale HTML (purge it), or a plugin or theme that explicitly enqueues jquery-migrate by handle rather than relying on the default dependency, in which case you have to track down and remove that enqueue too. If the script is gone but the console now shows new errors that were not there before, something needed Migrate after all: that is the test in the previous section catching you a step late, so put it back and fix the offending code first.

See also

Sources

Authoritative references this article was fact-checked against.

TagsWordPressPerformancePHPjQuerywp_default_scriptsPage Speed

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Add a Custom WP-CLI Command in WordPress

How to register a custom WP-CLI command: guard it with defined('WP_CLI'), wire it up with WP_CLI::add_command(), turn class methods into subcommands, document args with @synopsis, and show progress with make_progress_bar().