A config form's buildForm() can save whatever keys you tell it to — Drupal's form-building code has no idea what "correct" looks like for your data. A config schema is the missing rulebook: a YAML file that says, for every key your config form saves, exactly what data type it must be and whether it's translatable. Without one, every value silently arrives as a raw, untyped string, and your config is invisible to translation and config-inspection tooling.
What you'll learn in this lesson
- Where schema files live and how Drupal discovers them automatically
- The
config_objectbase type used for simple settings config - Why the
texttype matters specifically because it's translatable by default - How an unschematized key silently breaks translation and type safety
A real schema file
config_simple_example.settings:
# A config_object is a configuration object which can store fields.
# You have to map all field types the object stores: string, boolean, etc.
# The "text" field type is special because it's translatable by default.
# Checkout how to define schema and all available data types in:
# https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-schemametadata
type: config_object
label: 'Example config'
mapping:
message:
type: text
label: 'Message'
How it works
File location and auto-discovery
Schema files live in a module's config/schema/ directory, named <module_name>.schema.yml. That's the entire registration step — Drupal scans every enabled module for this exact path pattern at bootstrap. Nothing needs declaring in .info.yml, and there's no hook to implement.
The top-level key matches the config object's own name
config_simple_example.settings:
Unlike a config entity schema (which uses a glob pattern like module.type.* to cover many instances), a simple settings object's schema key is the literal, exact name of the one config object it describes — config_simple_example.settings, matching both the form's getEditableConfigNames() value and the actual saved file config_simple_example.settings.yml.
type: config_object
type: config_object
This is the base type for plain settings config — as opposed to config_entity, which you'd use for a config entity type with its own id/uuid/langcode fields. A simple settings object doesn't have those, so config_object is the correct, lighter-weight choice.
mapping: and the text type
mapping:
message:
type: text
label: 'Message'
Every key your config actually stores needs an entry here. message is typed text rather than plain string specifically because text is translatable by default through Drupal's Interface Translation system — appropriate for a longer, user-facing message. A short, non-translatable machine value would instead use string; a translatable short label would use label.
buildForm() without adding a matching entry to the schema's mapping. The form will still save the value — Drupal doesn't block an unschematized save — but that value stays untyped, untranslatable, and invisible to tools like the Configuration Inspector until you fix the schema.Quick check: if
messagewere typedstringinstead oftext, what would you lose? (Answer: translatability through the Interface Translation system —stringandtextstore the same kind of value, but onlytextis translatable by default. You'd need to add explicittranslatable: truemetadata to get the same behavior withstring.)
Key takeaways
- Schema files go in
config/schema/<module_name>.schema.ymland are auto-discovered — no registration step required. - Use
type: config_objectfor plain settings; reservetype: config_entityfor config entity types with their own id/uuid/langcode. - Prefer
type: textovertype: stringfor any translatable, user-facing message — it's translatable by default. - Every key your form saves needs a matching entry under
mapping, or it silently stays untyped and untranslatable.
Coming up next
With the shape of the data declared, the next lesson, "Saving Configuration Data," covers the other half: how submitForm() actually writes the form's values back into this schema-typed config object.