Liferay DXP · extension lab · 8 min
28 client extensions and 25 OSGi modules — one working example of each common Liferay extension type, each with a README.
Liferay DXP · OSGi · Client Extensions · Java
Architecture
From the real repo — how the pieces fit.
CX Lab
28 client extensions · 25 OSGi modules · one workspace
modules/
25 · OSGi · inside DXP
APIs & data
Sign-in
Admin
Content / search / WF
Language · Commerce
client-extensions/
28 · outside the portal
Browser
Theme
Config & data
Microservices
Commerce jobs
Client extension when it can live outside · Module when you need portal internals
Deck
Short overview of modules vs client extensions — open here or download the PPTX.
CX Lab is a Liferay workspace with one small, working example of every common extension type. Each project has its own README: what it is, why to use it, when to use it, how it works, and how to try it.
What it is
A test bench for Liferay DXP (Java 21, Node 22, Gradle). It does not ship a portal — point liferay.workspace.home.dir at your DXP home, then build and deploy. Source: codepapu/liferay-cx-lab.
There are two folders:
client-extensions/— 28 projects that run outside the portal JVM (browser widgets, theme bits, batch, microservices, Commerce engines).modules/— 25 OSGi modules that run inside the portal JVM (REST, Service Builder, sign-in, Control Panel, content, Commerce).
Two ways to extend
- OSGi module — inside the portal. Full access to Liferay services, permissions, and lifecycle.
- Client extension — outside the portal. Deploy and upgrade on its own; talks to Liferay over Headless APIs and OAuth 2.
Client extensions (28)
Full list from client-extensions/README.md. Open a name to see that project on GitHub.
Browser13
- cx-lab-hello-tilecustomElement
Plain JavaScript widget that greets the signed-in user, using a shared import map module.
- cx-lab-date-helpersjsImportMapsEntry
Publishes the shared ES module cx-lab-dates.
- cx-lab-profile-cardcustomElement
React 18 + TypeScript + Vite widget calling Headless as the signed-in user.
- cx-lab-book-shelfcustomElement
Lists the site’s books through the library GraphQL API, with search, paging, and a chart.
- cx-lab-status-frameiframe
Embeds an external page as a widget.
- cx-lab-cookie-bannerglobalJS
Dismissible cookie notice on every page where it is enabled.
- cx-lab-brand-accentsglobalCSS
Focus outlines and two utility classes on top of any theme.
- cx-lab-help-assetsstaticContent
JSON and SVG files served at a stable URL.
- cx-lab-lean-editoreditorConfigContributor
Trims the CKEditor 5 toolbar for chosen editors.
- cx-lab-status-pillfdsCellRenderer
Workflow status as a coloured label in Frontend Data Set tables.
- cx-lab-keyword-filterfdsFilter
“Contains” keyword filter for Frontend Data Sets.
- cx-lab-visitor-traitsaudiencesCustomAttributes
Colour scheme and viewport size as Audiences attributes.
- cx-lab-turnstile-widgetcustomElement (hidden)
Browser half of the Turnstile CAPTCHA.
Theme3
Configuration and data3
Microservices3
- cx-lab-business-serviceobjectAction · validation · entryManager · workflow · notification · captcha
Spring Boot 3.5 service on port 58081 hosting six server-side hooks.
- cx-lab-node-hooksobjectAction
Same kind of hook in Node.js + Express on port 3001.
- cx-lab-nightly-reportscheduled job
Counts user accounts through Headless, logs the number, and exits.
Commerce6
- cx-lab-pay-latercommercePaymentIntegration
Offline “pay by invoice” payment method (port 58082).
- cx-lab-flat-rate-shippingcommerceShippingEngine
Standard and express shipping rates (port 58083).
- cx-lab-region-taxcommerceTaxEngine
Default and reduced tax rates (port 58084).
- cx-lab-po-number-stepcommerceCheckoutStep
Extra checkout step for a purchase order number (port 58085).
- cx-lab-store-batchbatch
Imports a store (catalog, channel, warehouse, options, products, stock, price list) on deploy.
- cx-lab-store-headlessone-off job
Builds the same store through Headless Commerce Admin APIs, then exits.
OSGi modules (25)
Full list from modules/README.md. Each module runs inside the portal JVM.
APIs and data5
- cx-lab-librarycom.cxlab.library.*
Site-scoped Book catalog: Service Builder, permissions, MVC portlet, REST, GraphQL, Java client.
- cx-lab-isbncom.cxlab.isbn.*
ISBN validator as an API bundle plus a swappable implementation.
- cx-lab-book-statscom.cxlab.book.stats
Cached site totals: portal cache, model listener, scheduled warm-up, ETag / 304.
- cx-lab-greeting-restcom.cxlab.greeting.rest
JAX-RS endpoint with a System Settings value.
- cx-lab-api-guardcom.cxlab.api.guard
Rate limit and security headers for every CX Lab REST app, plus a sign-in failure alert.
Sign-in3
- cx-lab-login-webcom.cxlab.login.web
Custom sign-in widget with forgot-password and create-account views.
- cx-lab-login-customizercom.cxlab.login.customizer
Extends Liferay’s own sign-in page without copying its JSPs.
- cx-lab-login-pipelinecom.cxlab.login.pipeline
Authenticator, post-login and pre-logout actions, trusted-header auto login.
Administration6
- cx-lab-log-viewercom.cxlab.log.viewer
Read and filter the portal log files in the Control Panel.
- cx-lab-deployercom.cxlab.deployer
Upload a CX Lab jar or client extension zip to the deploy folder (off by default).
- cx-lab-seocom.cxlab.seo
Audits each page’s SEO settings and whether it is in sitemap.xml.
- cx-lab-dispatch-taskcom.cxlab.dispatch.task
Job Scheduler task: inactive users report.
- cx-lab-gogo-commandscom.cxlab.gogo.commands
cxlab:extensions and cxlab:sites in the Gogo shell.
- cx-lab-user-audit-listenercom.cxlab.user.audit.listener
Logs every user created or removed.
Content, search, and workflow5
- cx-lab-web-contentcom.cxlab.web.content
Web content structure, FreeMarker template, and sample article.
- cx-lab-blogscom.cxlab.blogs
Blogs widget template and sample entries.
- cx-lab-fragmentscom.cxlab.fragments
Page fragments shipped inside a module.
- cx-lab-search-blueprintcom.cxlab.search.blueprint
Search Blueprint and Element, plus a widget comparing results.
- cx-lab-workflowcom.cxlab.workflow
Two-step review workflow with Java action executors.
Language and localization4
- cx-lab-langcom.cxlab.lang
Shared translations in five languages, no Java.
- cx-lab-language-overridecom.cxlab.language.override
Changes existing portal and module text without touching its owner.
- cx-lab-localization-webcom.cxlab.localization.web
Live guide to every way to localize text.
- cx-lab-jsp-guide-webcom.cxlab.jsp.guide.web
Live guide to JSP, EL, and JSTL.
Commerce2
Try it
# point at your DXP home in gradle.properties
./gradlew deploy
# or one project
./gradlew :client-extensions:cx-lab-hello-tile:deploy
./gradlew :modules:cx-lab-greeting-rest:deployAfter modules deploy, lb -s com.cxlab in Gogo should list them as Active. Microservices also need their own process (see each project README for bootRun / yarn start).