Drupal 10 dropped jQuery's .once() plugin and replaced it with a standalone once() library. This is the single most common breakage point in Drupal 9 → 10 module upgrades, and it fails silently in a way that's easy to miss in testing.
What changed and why
In Drupal 9, jQuery was a hard dependency and .once() was a jQuery plugin. Drupal 10 began decoupling from jQuery. The once() functionality was extracted into its own standalone library — same behaviour, completely different API.
// Drupal 9 — jQuery .once()
Drupal.behaviors.myBehavior = {
attach: function (context) {
$(context).find('.my-element').once('myBehavior').each(function () {
// runs once per element
});
}
};// Drupal 10 — standalone once()
Drupal.behaviors.myBehavior = {
attach: function (context) {
once('myBehavior', '.my-element', context).forEach(function (el) {
// runs once per element
});
}
};The library declaration
You also need to update your .libraries.yml — otherwise once won't be available at runtime even if the syntax is correct.
# mymodule.libraries.yml
mymodule/behaviors:
js:
js/my-behavior.js: {}
dependencies:
- core/once # <-- required in Drupal 10
- core/drupalMigration tip: Run grep -r "\.once(" web/modules/custom to find every occurrence across your custom modules at once. There are usually more than you expect. Check contrib modules too — not all have been updated.
The removal of jQuery as a hard dependency
Drupal 10 still ships jQuery but it's no longer automatically loaded on every page. If your custom modules use jQuery directly, add core/jquery to your libraries dependencies explicitly. Don't assume it's there.