Service Container Architecture
When to Use
When you need to understand how Drupal's service container works under the hood — essential for debugging, optimization, and advanced patterns.
Decision
| Component | Purpose | When It Runs |
|---|---|---|
| ServiceProviderInterface | Register new services programmatically | Container compilation (cache rebuild) |
| ServiceModifierInterface | Alter existing service definitions | Container compilation, after all services registered |
| Compiler passes | Process tagged services, validate definitions | Container compilation, multiple phases |
| ContainerBuilder | Build the service container from YAML + providers | Cache rebuild, install, update |
| Container (compiled) | Runtime service instantiation and dependency resolution | Every request |
Pattern
Container Lifecycle:
// 1. DrupalKernel initializes container
// 2. Load all *.services.yml files
// 3. Execute service providers (register phase)
// 4. Execute service providers (alter phase)
// 5. Execute compiler passes
// 6. Compile container to PHP code
// 7. Cache compiled container
// 8. Runtime: load cached container, instantiate services on-demand
The container uses lazy instantiation — services are only created when first requested, not at container build time.
Reference: /core/lib/Drupal/Core/DrupalKernel.php, /core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php
Common Mistakes
- Assuming container is available everywhere — Container isn't initialized during install, some bootstrap phases
- Modifying services after container compilation — Changes to *.services.yml require cache rebuild
- Expecting services to be singletons without 'shared: false' — Services are shared (singleton) by default in Drupal
- Not understanding compilation vs runtime — Service providers run at compile time, services instantiate at runtime
- Forgetting Symfony versioning — Drupal 10 = Symfony 6.x, Drupal 11 = Symfony 7.x (check Symfony docs for version-specific features)