Configuration scheme
Drupal 8 includes support for a configuration schema/metadata language based on Kwalify (http://www.kuwata-lab.com/kwalify/) for YAML configuration files. Kwalify itself is written in Ruby and required some modifications for our purposes, so not all Kwalify details apply directly, but it's quite close.
Cheatsheet
For a quick understanding and some helpful examples, refer to this cheat sheet, and continue reading if you still have questions:
![]()
/sites/default/files/config-schema-cheat-sheet1.5.pdf
Introductory Example
The System module has two configuration parameters related to maintenance mode (whether the site is in offline mode for visitors):
<?php
$config = \Drupal::config('system.maintenance');
$message = $config->get('message');
$langcode = $config->get('langcode');
?>
(Note: Whether maintenance is enabled is stored in the state system, not configuration.)
The default values for this configuration object are stored in core/modules/system/config/install/system.maintenance.yml as:
message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.' langcode: en
Each module can have as many configuration objects as needed. These are defined in one or more schema files provided with the module. In the System module, these files are found in core/modules/system/config/schema. The relevant section from system.schema.yml looks like:
system.maintenance:
type: config_object
label: 'Maintenance mode'
mapping:
message:
type: text
label: 'Message to display when in maintenance mode'
The top-level key (system.maintenance) in the schema file corresponds to the base filename system.maintenance.yml and to the configuration object name config('system.maintenance'). The nested levels describe what is inside the file. Configuration schema predefines two file types: config_object for global configuration files and config_entity for entities. config_object is defined in core.data_types.schema.yml as:
# Root of a configuration object.
_core_config_info:
type: mapping
mapping:
default_config_hash:
type: string
label: 'Default configuration hash'
config_object:
type: mapping
mapping:
langcode:
type: string
label: 'Language code'
_core:
type: _core_config_info
The mapping type is a basic type for key-value pairs. Using config_object, the maintenance mode schema reuses keys langcode and _core and adds a message key. The label: 'Maintenance mode' describes the schema’s contents. The mapping section defines message while inheriting langcode and _core from the base type. Each item has a type and label key describing the data and its UI label.
In all core-supported cases, the top-level item in the .yml config file is a mapping described by the schema’s mapping list. You should use either config_object or config_entity subtypes. Items in the mapping can be of any type depending on the data. The _core key and all keys within it are reserved for Drupal core.
What Are Schema Files Used For?
1. To support multilingual features. We need tools to identify all translatable strings in shipped configuration so that we can offer translation suggestions via https://localize.drupal.org.
2. Schemas are used to create translation forms for config settings. The schema guides what fields are shown and how they behave in the translation UI.
3. Configuration schema is used by the persistence layer to correctly export configuration. You can skip writing schema if you implement toArray() in your config entity.
4. Schemas enforce value typecasting (e.g., strings vs integers) so deployment diffs reflect real changes and not accidental type changes.
5. PHPUnit's TestBase enforces default schema compliance. You can disable this with:
protected $strictConfigSchema = FALSE;
See https://drupal.org/project/config_inspector for a module that helps debug and inspect your schema.
There are more advanced use cases, such as generating web service interfaces based on schema metadata.
Properties
- type: The value's type; can be a base or derived type (see examples below).
- label: A UI label for the value. It does not have to match the form label exactly, but consistency improves clarity.
- translatable: Indicates whether the value should be translatable. You can use:
type: label
as a shorthand for:
type: string translatable: true
- nullable: Whether the value can be null. Defaults to false if not specified.
- class: Used for base types to assign a parsing class (examples below for TypedData and config types).
- Type-specific properties:
mapping: Used for mapping types, listing the keys and value types.
sequence: Used for sequence types, listing the type of elements in a list.
Types Supported in Schema Files
As mentioned, basic types and some complex types are defined in core.data_types.schema.yml:
undefined: label: 'Undefined' class: '\Drupal\Core\Config\Schema\Undefined' ignore: label: 'Ignore' class: '\Drupal\Core\Config\Schema\Ignore' boolean: label: 'Boolean' class: '\Drupal\Core\TypedData\Plugin\DataType\BooleanData' email: label: 'Email' class: '\Drupal\Core\TypedData\Plugin\DataType\Email' integer: label: 'Integer' class: '\Drupal\Core\TypedData\Plugin\DataType\IntegerData' float: label: 'Float' class: '\Drupal\Core\TypedData\Plugin\DataType\FloatData' string: label: 'String' class: '\Drupal\Core\TypedData\Plugin\DataType\StringData' uri: label: 'Uri' class: '\Drupal\Core\TypedData\Plugin\DataType\Uri'
Complex types:
mapping: label: Mapping class: '\Drupal\Core\Config\Schema\Mapping' definition_class: '\Drupal\Core\TypedData\MapDataDefinition' sequence: label: Sequence class: '\Drupal\Core\Config\Schema\Sequence' definition_class: '\Drupal\Core\TypedData\ListDataDefinition'
Mappings are associative arrays with explicitly defined keys. Sequences are indexed arrays where all items are of the same type.
Example Custom Complex Type
Defining a reusable "mail" type for email configuration:
mail:
type: mapping
label: 'Mail'
mapping:
subject:
type: label
label: 'Subject'
body:
type: text
label: 'Body'
This "mail" type can be reused in schemas, such as:
user.mail:
type: config_object
label: 'Email settings'
mapping:
cancel_confirm:
type: mail
label: 'Account cancellation confirmation'
password_reset:
type: mail
label: 'Password recovery'
Dynamic Type References
Types can be dynamic using placeholders:
[%key]: Uses the current key name[%parent]: Uses a parent key- Combos like
views.field.[table]-[field]
Example: image effects depend on the id field, so schema must dynamically reference that.
Naming Your Schema Files
Use globally unique names, preferably prefixed with your module name, to avoid conflicts.
Schema File Coding Style
- Use single quotes for all strings
- Do not quote keys or type names
- Use consistent indentation (YAML requires it)
- Provide meaningful labels for translatable strings
PHP API
To access typed configuration metadata:
$definition = \Drupal::service('config.typed')->getDefinition('system.maintenance');
Debugging Your Schema
Use the Config Inspector module to debug schema issues, check for missing types, and preview generated forms.