diff --git a/modules/geocoder_field/geocoder_field.module b/modules/geocoder_field/geocoder_field.module
index 0231fcddc5716ea426df0a22aac16e167fa4dc16..f144e26512ca85ef319886650c5e2fd7e94a9663 100644
--- a/modules/geocoder_field/geocoder_field.module
+++ b/modules/geocoder_field/geocoder_field.module
@@ -163,9 +163,14 @@ function geocoder_field_entity_presave(EntityInterface $entity) {
     return;
   }
 
+  // Skip any action if requested.
   $geocoder_config = \Drupal::configFactory()->get('geocoder.settings');
-  // Check geocoder_presave_disabled setting and do nothing if enabled.
-  if ($geocoder_config->get('geocoder_presave_disabled')) {
+  $config_disabled = $geocoder_config->get('geocoder_presave_disabled');
+  // Check if geocoder presave is disabled at runtime by a request attribute.
+  // i.e. via WorkspacePublishingSubscriber
+  // (@see https://www.drupal.org/i/3301512)
+  $runtime_disabled = \Drupal::request()->attributes->get('geocoder_presave_disabled', FALSE);
+  if ($config_disabled || $runtime_disabled) {
     return;
   }
 
diff --git a/modules/geocoder_field/geocoder_field.services.yml b/modules/geocoder_field/geocoder_field.services.yml
index 1bcd1c0dced23b95f73dea2252cccfed3d869172..98767805053dd91e6b96ef27494acc5701bf8f46 100644
--- a/modules/geocoder_field/geocoder_field.services.yml
+++ b/modules/geocoder_field/geocoder_field.services.yml
@@ -9,3 +9,9 @@ services:
     class: Drupal\geocoder_field\PreprocessorPluginManager
     parent: default_plugin_manager
     arguments: ["@country_manager"]
+
+  geocoder_field.workspace_publishing_subscriber:
+    class: Drupal\geocoder_field\EventSubscriber\WorkspacePublishingSubscriber
+    arguments: ['@request_stack']
+    tags:
+      - { name: event_subscriber }
diff --git a/modules/geocoder_field/src/EventSubscriber/WorkspacePublishingSubscriber.php b/modules/geocoder_field/src/EventSubscriber/WorkspacePublishingSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..460ff3fe127f8e9575af4687e085c100ca5593b9
--- /dev/null
+++ b/modules/geocoder_field/src/EventSubscriber/WorkspacePublishingSubscriber.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\geocoder_field\EventSubscriber;
+
+use Drupal\workspaces\Event\WorkspacePostPublishEvent;
+use Drupal\workspaces\Event\WorkspacePrePublishEvent;
+use Drupal\workspaces\Event\WorkspacePublishEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Event subscriber to respond to workspace publishing events.
+ *
+ * The geocoding operations from geocoder_field_entity_presave() can be very
+ * expensive when updating many entities at once. Workspace publishing doesn't
+ * change any field data, it only re-saves the latest workspace-specific
+ * revision and sets it as the default one, so there is no need to update
+ * geocoding data.
+ *
+ * @see geocoder_field_entity_presave()
+ */
+class WorkspacePublishingSubscriber implements EventSubscriberInterface {
+
+  public function __construct(
+    protected RequestStack $requestStack,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    if (!class_exists(WorkspacePublishEvent::class)) {
+      return [];
+    }
+
+    return [
+      WorkspacePrePublishEvent::class => ['onPrePublish'],
+      WorkspacePostPublishEvent::class => ['onPostPublish'],
+    ];
+  }
+
+  /**
+   * Adds a custom request attribute to prevent geocoding updates.
+   */
+  public function onPrePublish(): void {
+    if ($request = $this->requestStack->getCurrentRequest()) {
+      $request->attributes->set('geocoder_presave_disabled', TRUE);
+    }
+  }
+
+  /**
+   * Removes the custom request attribute.
+   */
+  public function onPostPublish(): void {
+    if ($request = $this->requestStack->getCurrentRequest()) {
+      $request->attributes->remove('geocoder_presave_disabled');
+    }
+  }
+
+}