Drupal 10 Back End Development: Site Building, Module Development, Theming, Performance, and Security
What the exam expects
Back-end questions on Drupal 10 reward precise knowledge of the services and patterns that core itself uses. You should be fluent in the plugin system (annotations replaced by PHP attributes in D10 for many plugin types, with #[Attribute]-based discovery), the entity/field API, dependency injection via *.services.yml, and the routing/controller/access stack. Know the difference between a service definition, a service collector, and a tagged service. Understand config vs. state vs. content: configuration is exportable YAML (Config API, schema files for translations and typed config), state is per-environment runtime data, and content is fieldable entities stored in the database.
Theming and render pipeline
Candidates must know render arrays, cacheability metadata (#cache with contexts, tags, max-age), and how bubbleable metadata merges up the tree. Lazy builders and #lazy_builder placeholders, CacheableMetadata, and cache tags invalidation are frequent topics. Twig templates in Drupal 10 autoescape by default; |raw should be rare and justified. Preprocess functions and hook_theme are still core knowledge, alongside single-directory components.
Performance and security
Expect questions on BigPipe, dynamic page cache, and the database/entity query caching. For security, know the difference between checkPlain-style escaping (largely removed), Twig autoescaping, Xss::filter, and FormattableMarkup for safe HTML with placeholders. Access control uses AccessResult objects that are cacheable and combinable (andIf, orIf); returning a bare boolean loses cacheability and is a common trap. CSRF tokens, #access, and route requirements (_permission, _entity_access, _csrf_token) matter.
Worked rule of thumb
When a question asks why a block or page does not update after content changes, check cache tags first: does the render array carry the entity's cache tag (e.g., node:5)? If not, invalidation never reaches it. Add CacheableMetadata::createFromRenderArray() or set #cache['tags'] explicitly.
Traps
- Confusing
#cachecontexts(variation by user role, URL) withtags(invalidation). - Assuming annotations still drive all plugins in D10; many moved to attributes.
- Treating state as exportable configuration.
- Returning
TRUE/FALSEfrom access callbacks instead ofAccessResultwith cacheability.