OSGi
Understand OSGi — the module system that powers AEM. Learn what bundles, services, and components are, and how they work together in a real project.
Last reviewed: December 2024
🔍 What Is It?
OSGi (Open Services Gateway initiative) is a modular Java framework that AEM uses as its runtime. It provides:
- →Bundle System — JAR files with metadata that can be deployed independently
- →Service Registry — A registry where bundles publish and consume services
- →Component Model — Java classes (components) that are activated/deactivated by OSGi
- →Configuration Admin — A way to configure services without changing code
- →Lifecycle Management — Bundles can be installed, started, stopped, and updated at runtime
AEM itself is a collection of OSGi bundles. Your custom code is also packaged as OSGi bundles. The Felix console at /system/console is where you manage all of this.
🎯 Why Do We Need It?
Without OSGi:
- →All code runs in one big monolith
- →Updating one class requires restarting the entire server
- →No clean way to manage dependencies between modules
- →No runtime configuration without code changes
With OSGi:
- →Deploy your bundle without restarting AEM
- →Each bundle manages its own dependencies
- →Services are loosely coupled — easy to swap implementations
- →Configuration can be changed at runtime via the Felix console
- →Third-party libraries are isolated — no classpath conflicts
In AEM projects, OSGi is where your business logic lives — services that call APIs, process data, send emails, or connect to databases.
🏗️ What Happens in Real Projects?
Real Project Usage:
OSGi Services:
- →EmailService — sends transactional emails
- →SearchService — queries the JCR or external search
- →ProductService — fetches product data from a PIM system
- →TranslationService — integrates with a translation API
- →CacheService — manages application-level caching
OSGi Configuration:
- →API endpoints (different for dev/staging/prod)
- →Feature flags
- →Cache TTL values
- →Email server settings
- →Third-party API keys
In your AEM Maven project:
Your custom code lives in the core module, which builds to an OSGi bundle (JAR). This bundle is packaged in your content package and deployed to AEM.
⚙️ How It Works
Bundle Lifecycle:
- Installed — Bundle JAR is in AEM but dependencies aren't resolved yet
- Resolved — All dependencies are satisfied
- Starting — Bundle's activator is running
- Active — Bundle is running normally
- Stopping — Bundle is shutting down
- Uninstalled — Bundle is removed
OSGi Components (@Component):
A class annotated with @Component is managed by OSGi. It has:
- →
@Activate— runs when the component starts - →
@Deactivate— runs when the component stops - →
@Modified— runs when configuration changes
OSGi Services (@Service):
A component that implements an interface and is registered in the service registry. Other components can inject it using @Reference.
OSGi Configuration:
Configuration is stored in the JCR under /apps/myproject/config/ or in /conf. Different configurations for different environments (author, publish, dev, prod) are managed via run modes.
Run Modes:
- →
/apps/myproject/config/— applies to all environments - →
/apps/myproject/config.author/— author only - →
/apps/myproject/config.publish/— publish only - →
/apps/myproject/config.dev/— dev environment only
💻 Example
Creating an OSGi Service — A complete example of an OSGi service with configuration, from interface to implementation.
🤔 Common Confusions
❓ What is the difference between @Component and @Service in OSGi?
@Component marks a class as managed by OSGi (lifecycle management). @Service (or service = MyInterface.class in @Component) registers it in the OSGi service registry so other components can inject it. Every service is a component, but not every component is a service.
❓ Why is my OSGi bundle in "Installed" state instead of "Active"?
Usually means unresolved dependencies — a package your bundle imports isn't exported by any other bundle. Check the Felix console (/system/console/bundles) and click on your bundle to see which imports are missing.
❓ What is the difference between @Activate and @PostConstruct?
@Activate is an OSGi lifecycle method — it runs when the OSGi component starts and receives OSGi configuration. @PostConstruct is a Sling Model lifecycle method — it runs after all injections complete. They're different frameworks.
❓ How do I configure different settings for Author vs Publish?
Use run mode folders: /apps/myproject/config/ for shared config, /apps/myproject/config.author/ for author-only, /apps/myproject/config.publish/ for publish-only. AEM automatically loads the right config based on the instance type.
🚨 Common Production Issues
Bundle in "Installed" state
missing dependency. Check /system/console/bundles and look for unresolved imports.
Service returns null in Sling Model
the bundle is not active, or the service interface doesn't match. Check Felix console.
Configuration not loading
OSGi config file name must exactly match the PID (class name). One character difference means it won't load.
NullPointerException in @Activate
configuration value is null. Always provide defaults in the @ObjectClassDefinition.
Service works on Author but not Publish
the bundle is deployed to Author but not Publish, or the config in config.publish/ is wrong.
Cloud Service config works in Dev but not Stage/Prod
a Cloud Manager variable or secret is missing, scoped to the wrong service, or named differently than the OSGi placeholder.
Thread-safety issue under load
an OSGi service stores request-specific mutable state in fields. Services are shared and must be treated as singleton components.
External integration causes slow pages
service has no timeout, retry limit, or fallback behavior for downstream API failures.
✅ Best Practices
Always define a service interface separate from the implementation
it makes testing and swapping implementations easy.
Use @Activate/@Modified with the same method to handle both initial activation and configuration changes.
Always provide sensible defaults in @ObjectClassDefinition
never let a service fail because a config value is missing.
Use SLF4J Logger (not System.out) for all logging in OSGi services.
Keep services focused on one responsibility
don't create a "GodService" that does everything.
Use @Reference(cardinality = ReferenceCardinality.OPTIONAL) for optional service dependencies.
Keep OSGi services stateless or protect shared state with clear concurrency rules.
In AEM as a Cloud Service, keep stable non-secret values in JSON configs and use Cloud Manager secrets only for sensitive values.
Add health-check style logging for critical integrations so support teams can quickly distinguish config issues from downstream outages.
🏛️ Architect's Note
OSGi is the backbone of AEM's extensibility. Understanding it deeply separates senior AEM developers from junior ones.
Service Design Principles:
- →Design services around interfaces, not implementations
- →Keep services stateless when possible — state in services causes threading issues
- →Use OSGi configuration for environment-specific values (API keys, endpoints, feature flags)
For AEM as a Cloud Service: OSGi configuration is deployed as code using JSON configs. Cloud Manager environment variables and secrets are used for values that cannot or should not be committed to Git, especially secrets and values that differ by environment.
Testing OSGi Services: Use the AemContext from wcm.io testing to register mock services. This is critical — services that call external APIs must be testable without hitting real APIs.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
↗ Where this topic fits
AEM Technology Guide
Return to the AEM learning hub.
AEM Developer Career Path
This AEM developer career path explains how to become an AEM developer through JCR, Sling, HTL, client libraries, Dispatcher, Cloud Service delivery, project depth, and interview-ready enterprise implementation skills.
Drupal Developer Career Path
A practical route through Drupal content modeling, site building, theming, modules, configuration management, APIs, performance, deployment discipline, and interview preparation.
Sources
Sources / References
Use these AEM references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide AEM learning path
Browse the full AEM topic collection and learning order on SplashRide.
AEM Interview Prep
Practice AEM interview questions and scenario-based answers.
AEM Developer Career Path
This AEM developer career path explains how to become an AEM developer through JCR, Sling, HTL, client libraries, Dispatcher, Cloud Service delivery, project depth, and interview-ready enterprise implementation skills.
Drupal Developer Career Path
A practical route through Drupal content modeling, site building, theming, modules, configuration management, APIs, performance, deployment discipline, and interview preparation.
Sling Models
Understand Sling Models — the backbone of AEM component logic. Learn how they work, how to write them, and the gotchas that trip up every developer.
Apache Sling
Understand Apache Sling — the web framework that powers AEM's URL resolution, request processing, and resource-centric architecture.