What is the correct way to update my cached block when a node of a given type is saved or updated? I have a custom module with a block plugin:

SliderBlock.php

class SliderBlock extends BlockBase {
  public function build() {
    $build = [];
    $build['#theme'] = 'slider_block';

    return $build;
  }
}


I want to render a list of nodes of type 'slides' in the block (it will eventually be a custom slider feature)

mymodule.module

function mymodule_theme() {
  return [
    'slides_block' =&gt; [
      'variables' =&gt; [
        'slides' =&gt; get_slides(),
      ],
    ],
  ];
}

function get_slides() {
  // Load all slides nodes.
  $nids = \Drupal::entityQuery('node')
    -&gt;condition('type','slides')
    -&gt;condition('status','1') // Only published slides nodes.
    -&gt;execute();
  $nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);

  return $nodes;
}


and I loop over each in the template to get the markup I need:

slider-block.html.twig

{# markup for slider here #}
{% for slide in slides %}
  &lt;p&gt;{{ slide.label }}&lt;/p&gt;
{% endfor %}


The above template shows me the title field for each Slides node, which is what I expect. The problem is that if I un-publish a Slides node, the markup is not updated unless I clear caches.

Alright, this sounds like a cache issue, so I dove into a google search mission and discovered a series of ways to disable caching for the block. None of which seem to work, for anonymous users or otherwise:

// Unsuccessful:
public function getCacheMaxAge() {
  return 0;
}

// Unsuccessful:
$build['#cache'] = [
  'max-age' =&gt; 0,
];


I looked at cache contexts, as far as I could tell, there was no 'node' based cache context. If I understood them correctly, cache tags wouldn't help, since I don't know the ids of any given node of type 'Slides'.

I 'only want to' disable caching for this block. This block will be rendered only on a specific page, so I could disable caching on that page using the modules route yml file (am I right?), but it feels wrong to disable that whole page for the sake of one block.

What is the right way to solve this, and what's the methodology in reaching that conclusion?

Note: I could use views to collect the nodes, but to customise the view markup is more  challenging.
As @Clive commented you need a node list cache tag.

Put the slides and the cache tag when you invoke the template in the build array (not in a hook_theme(), this hook is only called when you install the module):

class SliderBlock extends BlockBase {
  public function build() {
    $build = [
     '#theme' =&gt; 'slider_block',
     '#slides' =&gt; getSlides(),
     '#cache' =&gt; ['tags' =&gt; ['node_list']],
    ];
    return $build;
  }
}


Put a TODO annotation in your code to change the list tag to a content type specific node_list:slides, once you have updated to Drupal 8.9.x. See this change record: Added an ENTITY_TYPE_list:BUNDLE cache tag.