Main Answer: Liferay Client Extensions decouple customizations from the core Liferay JVM. Unlike legacy OSGi modules, which deploy custom Java code directly into the container, Client Extensions run outside the portal and communicate using REST webhooks and JavaScript APIs, eliminating upgrade friction and ensuring SaaS compatibility.
Audience: Written for Liferay DXP developers, portal architects, and administrators migrating custom plugins to cloud environments.
Applicable Use Cases: Headless setups, SaaS portal clouds, and multi-team environments building modular custom portlets.
| Feature comparison | Client Extensions | OSGi Modules |
|---|---|---|
| Decoupled from core JVM | Yes (Fully independent runtime) | No (Shares core OSGi container) |
| Upgrade compatibility | 100% cloud-safe (REST / microservices) | Requires recompilation and validation |
What Are the Architectural Differences Between Client Extensions and OSGi?
Direct Answer: Liferay OSGi modules run directly inside the portal's JVM memory space. This shared runtime architecture means a single memory leak, thread starvation, or classloader conflict in a custom bundle can crash the entire system. OSGi modules require local Java compile tasks, meaning custom code is tightly coupled with Liferay's internal API schemas.
Liferay OSGi modules run directly inside the portal's JVM memory space. This shared runtime architecture means a single memory leak, thread starvation, or classloader conflict in a custom bundle can crash the entire system. OSGi modules require local Java compile tasks, meaning custom code is tightly coupled with Liferay's internal API schemas.
In contrast, Liferay Client Extensions run completely decoupled from Liferay, interfacing exclusively via secure OAuth2 tokens and public REST interfaces. They deploy as configuration-driven metadata packages declared in a liferay-client-extension.yaml file. The portal loads front-end components from a CDN or local web server, completely separating custom runtimes from the core portal container.
In contrast, Liferay Client Extensions run completely decoupled from Liferay, interfacing exclusively via secure OAuth2 tokens and public REST interfaces. They deploy as configuration-driven metadata packages declared in a liferay-client-extension.yaml file. The portal loads front-end components from a CDN or local web server, completely separating custom runtimes from the core portal container.
What Are the Benefits of Decoupled Customization in Liferay DXP?
Direct Answer: By decoupling your customizations, you insulate the portal core from runtime application failures. This isolation delivers three major enterprise benefits:
By decoupling your customizations, you insulate the portal core from runtime application failures. This isolation delivers three major enterprise benefits:
- Seamless Upgrades: Major platform updates do not require compiling or refactoring legacy Java bundles. Platform APIs can evolve without breaking your external custom portlets.
- SaaS Compliance: Liferay Experience Cloud (LXC) SaaS deployments strictly forbid the deployment of custom OSGi modules to ensure cluster safety. Client Extensions are the mandatory path for cloud compliance.
- Development Independence: Front-end teams can build, bundle, and package custom widgets using modern tools (such as Vite, Webpack, React, Vue, or Tailwind) without any Java dependencies or Liferay workspace compilation overhead.
- Seamless Upgrades: Major platform updates do not require compiling or refactoring legacy Java bundles. Platform APIs can evolve without breaking your external custom portlets.
- SaaS Compliance: Liferay Experience Cloud (LXC) SaaS deployments strictly forbid the deployment of custom OSGi modules to ensure cluster safety. Client Extensions are the mandatory path for cloud compliance.
- Development Independence: Front-end teams can build, bundle, and package custom widgets using modern tools (such as Vite, Webpack, React, Vue, or Tailwind) without any Java dependencies or Liferay workspace compilation overhead.
How Do You Migrate Legacy OSGi Modules to Liferay Client Extensions?
Direct Answer: To successfully migrate an OSGi custom widget, follow this developer playbook based on official guidelines from the Liferay Learn Portal and the OSGi Alliance specifications:
To successfully migrate an OSGi custom widget, follow this developer playbook based on official guidelines from the Liferay Learn Portal and the OSGi Alliance specifications:
- Separate Visual Layouts from Database Logic: Extract JSP markups and frontend scripts from your legacy bundle. Rebuild the frontend layout as a standard Web Component (Custom Element) compiled into a single JS asset.
- Declare Metadata in YAML: Create a
liferay-client-extension.yamlconfiguration file. Define your extension, assigning it a unique ID, its type (such ascustom-element), and pointing it to your bundled JavaScript files. - Migrate Backend Logic to Liferay Objects: Replace legacy Service Builder database code with Liferay's native, low-code Objects. Objects automatically generate secure REST and GraphQL endpoints for data interactions.
- Implement Secure Webhooks for Logic Execution: Move any custom backend algorithms (previously written in Java) into a standalone microservice (written in Node.js, Python, or Go). Configure Liferay Object Actions to trigger REST webhook calls to this external microservice, secured using OAuth2 profiles.
For more detailed migration blueprints, you can browse other articles on the LiferayX Developer Blog or review our step-by-step developer guides in the Liferay DXP Guides section.
- Separate Visual Layouts from Database Logic: Extract JSP markups and frontend scripts from your legacy bundle. Rebuild the frontend layout as a standard Web Component (Custom Element) compiled into a single JS asset.
- Declare Metadata in YAML: Create a
liferay-client-extension.yamlconfiguration file. Define your extension, assigning it a unique ID, its type (such ascustom-element), and pointing it to your bundled JavaScript files. - Migrate Backend Logic to Liferay Objects: Replace legacy Service Builder database code with Liferay's native, low-code Objects. Objects automatically generate secure REST and GraphQL endpoints for data interactions.
- Implement Secure Webhooks for Logic Execution: Move any custom backend algorithms (previously written in Java) into a standalone microservice (written in Node.js, Python, or Go). Configure Liferay Object Actions to trigger REST webhook calls to this external microservice, secured using OAuth2 profiles.
For more detailed migration blueprints, you can browse other articles on the LiferayX Developer Blog or review our step-by-step developer guides in the Liferay DXP Guides section.
Frequently Asked Questions
Do Client Extensions require OSGi restarts?
No. Client Extensions deploy dynamically as configuration maps and do not require container restarts or downtime.
What languages can we use for backend Extensions?
Any language. Since backend extensions communicate via REST webhooks, you can write them in Node.js, Java, Python, Go, or .NET.