This was written as a blog-style contribution during "Contribution Day" at DrupalCon Pittsburgh 2023 to share some things that are going on in Drupal.
When Drupal module builders expose configuration options, it's good to set some constraints on what values are allowed. For example, you may require that users enter a positive integer, a non-empty string, or a valid date. Up to now this validation has been done in the Form API (in the form widget or form validation code), but all that validation can be bypassed when setting configuration values through other methods, such as PHP code, Drush, or (potentially in the future) JSON API.
Here's what I learned today about implementing configuration validation:
1 - Enable validation by putting `constraints` into the schema.
Constraints are the elements that make config validatable, and they go in your module's config/schema/[modulename].schema.yml file. That file lists all config entities that the module makes available. Today we focused on simple configs, such as a module's settings, rather than more complex configs, such as field types or other extensions of base configs.
Here's what a config file with constraints looks like:
```
jsonld.settings:
type: config_object
label: 'JSONLD Settings'
mapping:
remove_jsonld_format:
type: boolean
label: 'If checked, ?_format=jsonld will be stripped from the end of urls in JSONLD'
rdf_namespaces:
type: sequence
label: 'RDF Namespaces'
constraints:
UniqueLabelInList: {labelKey: prefix}
sequence:
type: mapping
orderby: key
mapping:
prefix:
type: string
label: 'RDF Prefix'
namespace:
type: string
label: 'Fully Qualified RDF Namespace'
constraints:
Url: {}
NotBlank: {}
```
The constraints are defined by the `constraints` key at various places in the schema. There are two places we applied constraints here, both in the `rdf_namespaces` element. This element corresponds to the form element where a user can enter key|value pairs to define prefixes and RDF namespaces:

Caption: The configuration form for the JsonLD module, showing the widget used to set RDF Namespaces as key|value pairs.
The first constraint, directly under `rdf_namespaces`, states that the sequence must have unique 'prefix' elements. This will fail if someone enters two rows with the same key. It is necessary to tell the constraint which part of the mapping is functioning as the unique key, by passing the `labelKey` option. The second place we added constraints is under the `namespace` element, and it makes sure that the namespace value is a valid URL, and not blank (since the `Url` validator does not complain if the value is empty). It does not take any options.
2 - Run the validator by using the Config Inspector module
To see if your configuration validates, first install the
Configuration Inspector (`config_inspector`) module. You can use Config Inspector's command line or the module's GUI.
On the command line:
`drush config:inspect --filter-keys=jsonld.settings --detail --list-constraints`
(replacing jsonld.settings with the key for your desired config, or omit to see all configuration. Other options include listing only errors, or treating elements missing constraints as errors).

Caption: the results of running `config:inspect` on the jsonld.settings, showing validation errors due to repeated keys and a non-URL namespace.
Alternately, navigate to the GUI at Reports > Configuration inspector. The same information is made available.
3 - Getting config to validate is a large work-in-progressAs of today (June 8 2023), config constraints are not applied when saving configuration. There's a significant amount of work to do first to make Drupal Core happily validating its config. The current parent issue is
KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate and there are sub-issues for fixing various issues that arose as part of this issue.
Eventually, constraint validation in the schema will be applied no matter how you attempt to write config entities. By adding constraints now, we can be ahead of the curve and take advantage of this awesome initiative. But it is also important to be smart about what constraints to apply. For example, I'm not 100% sure that it's wise to say that RDF namespaces must pass Url validation, it's possible that users might need to add other namespace values. A second caveat is that if we did want to state that namespaces must be valid URLs, we might want to use `type=uri` instead of `type=string`. That way the type validation would run automatically, and we could remove the explicit `constraints`.
Bonus:
What constraints are available? It's not super easy to find all the available constraints known to Drupal, but here are some techniques:
To list all constraints known to drupal, run
`vendor/bin/drush ev "print_r(array_keys(\Drupal::service('validation.constraint')->getDefinitions()))"`
My instance had 54 constraints available, such as `NotNull`, `UniqueLabelInList`, and `DateTimeFormat`. But there were also many more constraints existing in `vendor/symfony/validator/Constraints/` that are would be useful (such as `Url` and , though were not configured yet with Drupal! Nick Dickinson-Wilde
added over 30 of them in an issue against core, so that they can be used!
Modules can create their own validation constraints, by extending the `Symfony\Component\Validator\Constraint` class. We already can see an example of this in the Controlled Access Terms module's EDTF constraint. However, not all constraint plugins work well with config, since some (including EDTF) assume a Field entity, and won't work when we pass config in the form of a simple string or array as a value.