diff --git a/environment_indicator.module b/environment_indicator.module
index fffb6058462d61d86a2476019e3418814dc7ae94..2c33584fbc140b625418e94922f63e4bf4f8efca 100644
--- a/environment_indicator.module
+++ b/environment_indicator.module
@@ -126,8 +126,7 @@ function environment_indicator_page_top(array &$page_top) {
   }
   // Only add the environment indicator switcher if there are environments to
   // switch to.
-  if ($items = _environment_indicator_switcher_links()) {
-    uasort($items, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
+  if ($items = \Drupal::service('environment_indicator.switcher_manager')->getLinks()) {
     $page_top['indicator']['switcher'] = [
       '#theme' => 'links',
       '#links' => $items,
@@ -143,7 +142,7 @@ function environment_indicator_page_top(array &$page_top) {
     ];
     $page_top['indicator'] += [
       '#cache' => [
-        'tags' => Cache::mergeTags(['config:environment_indicator.settings'], _environment_indicator_switcher_cache_tags()),
+        'tags' => Cache::mergeTags(['config:environment_indicator.settings'], \Drupal::service('environment_indicator.switcher_manager')->getCacheTags()),
       ],
     ];
   }
@@ -230,6 +229,12 @@ function environment_indicator_toolbar() {
  *
  * @return array
  *   A renderable array with the links.
+ *
+ * @deprecated in environment_indicator:4.0.22 and is removed from environment_indicator:5.0.0.
+ *   Use
+ *   \Drupal::service('environment_indicator.switcher_manager')->getLinks()
+ *   instead.
+ * @see https://www.drupal.org/node/3526893
  */
 function _environment_indicator_switcher_links(): array {
   return \Drupal::service('environment_indicator.toolbar_handler')
@@ -255,6 +260,12 @@ function _environment_indicator_external_integration_is_enabled(string $integrat
  *
  * @return string[]
  *   The cache tags.
+ *
+ * @deprecated in environment_indicator:4.0.22 and is removed from environment_indicator:5.0.0.
+ *   Use
+ *   \Drupal::service('environment_indicator.switcher_manager')->getLinks()
+ *   instead.
+ * @see https://www.drupal.org/node/3526893
  */
 function _environment_indicator_switcher_cache_tags(): array {
   return \Drupal::service('environment_indicator.toolbar_handler')
diff --git a/environment_indicator.services.yml b/environment_indicator.services.yml
index 6115b4509a5da87b530c45716b9902adcd80e95a..7344a74c2b33dd26195260b42f0ab9c7e79eb7a8 100644
--- a/environment_indicator.services.yml
+++ b/environment_indicator.services.yml
@@ -8,3 +8,9 @@ services:
       - '@state'
       - '@settings'
       - '@entity_type.manager'
+      - '@environment_indicator.switcher_manager'
+  environment_indicator.switcher_manager:
+    class: Drupal\environment_indicator\Service\SwitcherManager
+    arguments:
+      - '@entity_type.manager'
+      - '@current_route_match'
diff --git a/src/Service/SwitcherManager.php b/src/Service/SwitcherManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..119199fcd0ee9e4fef86114722aa272f2223bff4
--- /dev/null
+++ b/src/Service/SwitcherManager.php
@@ -0,0 +1,109 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\environment_indicator\Service;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Routing\CurrentRouteMatch;
+use Drupal\Core\Url;
+
+/**
+ * Manages active environment switcher entities and builds UI-ready link data.
+ *
+ * This service centralizes logic related to the environment switcher list,
+ * including filtering active switchers and formatting their metadata as
+ * render-ready link arrays. It also provides cache tags to support proper
+ * cache invalidation when switcher configuration changes.
+ *
+ * Responsibilities:
+ * - Load and filter switchers based on status (and eventually permissions).
+ * - Build renderable links for UI components (e.g., page top, toolbar).
+ * - Provide cache tags related to switcher listings.
+ *
+ * Future enhancements may include:
+ * - Per-switcher access checks (once fixed in the module).
+ * - Domain/path/language-aware filtering.
+ * - Grouping, prioritization, or transformations.
+ *
+ * This service intentionally keeps responsibilities simple and centralized.
+ * If needed, future refactors may extract access filtering, link rendering,
+ * or entity loading into dedicated services or helpers.
+ */
+class SwitcherManager {
+
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected EntityTypeManagerInterface $entityTypeManager;
+
+  /**
+   * The current route match service.
+   *
+   * @var \Drupal\Core\Routing\CurrentRouteMatch
+   */
+  protected CurrentRouteMatch $routeMatch;
+
+  /**
+   * Constructs a new SwitcherManager instance.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   The entity type manager service.
+   * @param \Drupal\Core\Routing\CurrentRouteMatch $routeMatch
+   *   The current route match service.
+   */
+  public function __construct(EntityTypeManagerInterface $entityTypeManager, CurrentRouteMatch $routeMatch) {
+    $this->entityTypeManager = $entityTypeManager;
+    $this->routeMatch = $routeMatch;
+  }
+
+  /**
+   * Builds an array of environment switcher links.
+   *
+   * @return array[]
+   *   A render array of link definitions for each active environment.
+   */
+  public function getLinks(): array {
+    /** @var \Drupal\environment_indicator\Entity\EnvironmentIndicator[] $entities */
+    $entities = $this->entityTypeManager->getStorage('environment_indicator')->loadMultiple();
+
+    $current_path = Url::fromRoute('<current>')->toString();
+
+    $links = [];
+    foreach ($entities as $entity) {
+      if (!$entity->status() || empty($entity->getUrl())) {
+        continue;
+      }
+
+      $links[] = [
+        'attributes' => [
+          'style' => sprintf('color: %s; background-color: %s;', $entity->getFgColor(), $entity->getBgColor()),
+          'title' => t('Opens the current page in the selected environment.'),
+        ],
+        'title' => t('Open on @label', ['@label' => $entity->label()]),
+        'url' => Url::fromUri($entity->getUrl() . $current_path),
+        'type' => 'link',
+        'weight' => $entity->getWeight(),
+      ];
+    }
+
+    uasort($links, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
+
+    return $links;
+  }
+
+  /**
+   * Returns cache tags related to the switcher list.
+   *
+   * @return string[]
+   *   An array of cache tags.
+   */
+  public function getCacheTags(): array {
+    return $this->entityTypeManager
+      ->getDefinition('environment_indicator')
+      ->getListCacheTags();
+  }
+
+}
diff --git a/src/ToolbarHandler.php b/src/ToolbarHandler.php
index 10b1b8cef47a4008f72f8f9477fb74631c0bff48..b430e6efe4492ad26ff1d110912371d21984ce47 100644
--- a/src/ToolbarHandler.php
+++ b/src/ToolbarHandler.php
@@ -12,7 +12,7 @@ use Drupal\Core\Site\Settings;
 use Drupal\Core\State\StateInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
-use Drupal\environment_indicator\Entity\EnvironmentIndicator;
+use Drupal\environment_indicator\Service\SwitcherManager;
 
 /**
  * Toolbar integration handler.
@@ -70,6 +70,13 @@ class ToolbarHandler {
    */
   protected EntityTypeManagerInterface $entityTypeManager;
 
+  /**
+   * The SwitcherManager service.
+   *
+   * @var \Drupal\environment_indicator\Service\SwitcherManager
+   */
+  protected SwitcherManager $switcherManager;
+
   /**
    * ToolbarHandler constructor.
    *
@@ -85,6 +92,8 @@ class ToolbarHandler {
    *   The settings.
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
+   * @param \Drupal\environment_indicator\Service\Service\SwitcherManager $switcher_manager
+   *   The switcher manager service.
    */
   public function __construct(
     ModuleHandlerInterface $module_handler,
@@ -93,6 +102,7 @@ class ToolbarHandler {
     StateInterface $state,
     Settings $settings,
     EntityTypeManagerInterface $entity_type_manager,
+    SwitcherManager $switcher_manager,
   ) {
     $this->moduleHandler = $module_handler;
     $this->config = $config_factory->get('environment_indicator.settings');
@@ -101,6 +111,7 @@ class ToolbarHandler {
     $this->state = $state;
     $this->settings = $settings;
     $this->entityTypeManager = $entity_type_manager;
+    $this->switcherManager = $switcher_manager;
   }
 
   /**
@@ -206,7 +217,7 @@ class ToolbarHandler {
         ];
       }
 
-      if ($links = $this->getLinks()) {
+      if ($links = $this->switcherManager->getLinks()) {
         $items['environment_indicator']['tray']['environment_links'] = [
           '#theme' => 'links__toolbar_shortcuts',
           '#links' => $links,
@@ -311,6 +322,12 @@ class ToolbarHandler {
    *
    * @return array
    *   The cache tags.
+   *
+   * @deprecated in environment_indicator:4.0.22 and is removed from environment_indicator:5.0.0.
+   *   Use
+   *   \Drupal::service('environment_indicator.switcher_manager')->getCacheTags()
+   *   instead.
+   * @see https://www.drupal.org/node/3526893
    */
   public function getCacheTags(): array {
     return $this->entityTypeManager->getDefinition('environment_indicator')->getListCacheTags();
@@ -321,6 +338,12 @@ class ToolbarHandler {
    *
    * @return array
    *   Returns all the links.
+   *
+   * @deprecated in environment_indicator:4.0.22 and is removed from environment_indicator:5.0.0.
+   *   Use
+   *   \Drupal::service('environment_indicator.switcher_manager')->getLinks()
+   *   instead.
+   * @see https://www.drupal.org/node/3526893
    */
   public function getLinks(): array {
     if (!$environment_entities = EnvironmentIndicator::loadMultiple()) {