How can I remove all contextual links? When using the layout builder module, the contextual links module is a hard dependency. This works quite well in the context of the layout builder. But I don't want those links anywhere else, because elsewhere they are not helpful at best, and completly mess up my frontend theme at worst.

I've already written a custom theme negotiator to force my admin theme in layout building mode. 

But I don't know how to remove all contextual links when I'm in frontend. My current ugly hack is

function wt_cms_entity_view_alter(array &amp;$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  /**
   * Suppress the contextual edit pen on frontend themes, we only want it
   * for layout builder in admin theme
   */
  if (isset($build['#contextual_links'])) {
    $routeName = \Drupal::routeMatch()-&gt;getRouteName();
    if (!in_array($routeName, ['layout_builder.overrides.node.view', 'layout_builder.defaults.node.view'])) {
      unset($build['#contextual_links']);
    }
  }
}


and an additional rule in my frontend CSS

.contextual-toolbar-tab, [data-contextual-id] {
  display: none !important;
}


This does at least hide the contextual edit pen in frontend, but it does not really remove the contextual link menu. (There still is an empty placeholder div).

I've also tried @Shreya Shetty's suggestion

function mymodule_contextual_links_alter(array &amp;$links, $group, array $route_parameters) {
  $routeName = \Drupal::routeMatch()-&gt;getRouteName();  //incorrect, this always returns "contextual.render"
  if (!in_array($routeName, ['layout_builder.overrides.node.view', 'layout_builder.defaults.node.view'])) {
    $links = [];
  }
}


In contextual alter I've got other problems: The current $routeName is always contextual.render and not the route of the host page, so I've no "entry point" to specifically alter non-layout bulder-pages. It also has the same problem as the hook_entity_view_alter workaround: The menu items are suppressed, but the empty contextual placeholder divs are still rendered.

Can anyone tell me how to reliably and cleanly remove the contextual links? I don't want them anywhere, except in layout building mode.
It was a caching issue. This is my final code to cleanly hide all contextual links except in layout building mode:

use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;

function mymodule_page_attachments(array &amp;$page) {
  $routeName = \Drupal::routeMatch()-&gt;getRouteName();
  if (!in_array($routeName, ['layout_builder.overrides.node.view', 'layout_builder.defaults.node.view'])) {
    $page['#attached']['library'] = array_diff($page['#attached']['library'], ['contextual/drupal.contextual-links', 'contextual/drupal.contextual-toolbar']);
  }
}

function mymodule_entity_view_alter(array &amp;$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  $routeName = \Drupal::routeMatch()-&gt;getRouteName();
  if (!in_array($routeName, ['layout_builder.overrides.node.view', 'layout_builder.defaults.node.view'])) {
    unset($build['#contextual_links']);
  }
}


For the caching issue:
The changes above most likely will (after cache clearing) remove all contextual link entries, but leave an empty placeholder like &lt;div data-contextual-id="..." data-contextual-token="..."&gt;&lt;/div&gt; in your rendered HTML. To get rid off those empty divs, go to your browsers Developer console &gt; Application &gt; Session storage and clear all keys starting with Drupal.contextual. After clearing them, the empty placeholder divs are gone too, no more CSS hacking needed.