Retrieving configuration values programmaticallyfor Drupal 8 , 9 , 10 , and 11

Last updated :  

The weather module's settings form can now save an API key and a default location. But a settings form that only ever writes is useless — somewhere else in the module, real code (a block, a controller) needs to actually read those values back out to call the weather API. This lesson is that other half: retrieving configuration programmatically, safely and efficiently.

What you'll learn in this lesson

  • How to read a config value with config.factory from any service, controller, or block
  • Why you should always use the immutable get() for reading, never getEditable()
  • How to read one key vs. the whole config object at once
  • What happens when you read a key that was never set

Reading the weather module's API key

From inside a controller, service, or block plugin, reading a single value looks like this:

$api_key = \Drupal::config('weather_module.settings')->get('api_key');

if (empty($api_key)) {
  // Handle the "not configured yet" case explicitly.
  return ['#markup' => $this->t('Weather module is not configured yet.')];
}

\Drupal::config($name) is the procedural shortcut for the same config.factory service from the last lesson, just returning the immutable form — exactly what reading calls for. If you're inside a class that supports dependency injection (a controller, a service, a form), inject config.factory properly instead of calling the static \Drupal::config() helper, since it makes the dependency explicit and the class easier to unit test.

Reading one key vs. the whole object

// One specific value:
$location = \Drupal::config('weather_module.settings')->get('default_location');

// Every value in the config object, as an array:
$settings = \Drupal::config('weather_module.settings')->get();

Calling get() with no argument returns the entire config object's data as a nested array — handy when you need several related values at once, since it's one call instead of several. Calling it with a key does what you'd expect: returns just that value, or NULL if the key was never set.

A missing key is not an error. Unlike an undefined array index, reading a config key that was never saved just returns NULL quietly — Drupal does not throw or warn. This is exactly why the previous lesson on default configuration matters: without a shipped default, get('api_key') on a freshly installed site returns NULL, and your code needs to handle that explicitly, as the example above does.

Quick check: why does reading configuration always use get()/\Drupal::config() rather than getEditable(), even though getEditable() would technically still return the right value? (Answer: the immutable object returned by get() can be safely cached and shared across the whole request without any risk of unrelated code mutating it mid-request — using getEditable() everywhere would quietly defeat that caching and invite bugs where one part of the code accidentally changes config another part relies on.)

Key takeaways

  • Read configuration with the immutable get() (or \Drupal::config()), never getEditable() — reserve the editable form for actually writing.
  • get('key') returns one value or NULL if it was never set; get() with no argument returns the whole config object as an array.
  • A missing config key fails silently (returns NULL) rather than throwing — always code defensively around values that might not be set yet.
  • Prefer dependency-injecting config.factory in classes that support it, over the static \Drupal::config() helper.

Coming up next

That NULL-on-a-fresh-install problem is exactly what the next lesson solves: shipping a default configuration file so the weather module works with sensible defaults the moment it's installed, before anyone ever visits the settings form.