Release Notes
Contents
The headline features and themes for each XP feature release. For step-by-step upgrade instructions and the full breaking-change list, see Upgrading.
XP 8.1
This release includes a preview of the GraalJS engine, a more predictable scheduler, a Content Security Policy API, and a selection of smaller improvements and bugfixes. There are no breaking changes for applications. See the XP 8.1 upgrade notes for deprecations worth cleaning up.
GraalJS preview
GraalJS, the engine that will replace Nashorn, is available as a preview. It implements the current ECMAScript standard, where Nashorn stops at ES5.
Nashorn remains the default and the supported engine. The engine is chosen per application via the X-Script-Engine header in the bundle manifest, with the installation default set in system properties. A single app can be moved to GraalJS and back without affecting the others. The differences for application code - module state per context, disposer registration, executeFunction - are described in the dev kit documentation on JavaScript engines.
| GraalJS is not for production use. |
On both engines, main.ts now completes before anything else in the app runs on that node. Initialization code no longer needs guards against early requests.
Scheduler
Four changes make scheduled jobs more predictable in a cluster:
-
Control where the scheduler runs. Set
acceptScheduling = falseto keep a node out of scheduling - typically the master nodes, which must stay responsive to hold the quorum. Scheduling and the maintenance tasks it submits then run on a node that can afford the load. See scheduler configuration. -
Jobs do not overlap themselves. The scheduler checks whether the previous run is still going before submitting a new one. A blocked
CRONoccurrence is skipped, and a blockedFIXED_RATErun waits until its predecessor finishes. This is best effort - a partitioned cluster can still produce an overlap. See non-overlapping runs. -
New schedule type.
FIXED_RATEtakes an ISO-8601 duration, such as'PT5M'for every five minutes, for work that repeats at an interval rather than at a time of day. -
Self-deleting one-time jobs.
deleteAfterRunon aONE_TIMEschedule removes the job once it has fired.
A task started by the scheduler can read the previous run’s task id from the schedule.lastTaskId context attribute, useful for incremental processing; see what a scheduled task receives. Jobs declared in the scheduler config file are now created by the node that runs the scheduler, and new entries are picked up without a restart. See the scheduler library.
Content Security Policy as an API
A request-scoped CSP builder replaces hand-assembled header strings. One policy is shared for the whole request, so the page, its layouts, its parts and any response processor all contribute to a single header, nonce included. The header is composed when the response is flushed, so late contributions are not lost. A report-only companion lets you enforce one policy while trialling a stricter one. A Content-Security-Policy header set directly on the response is folded into the policy rather than sent as it is, so later contributions still apply. See csp() in the portal library.
Admin extensions get the same control over the tool page that hosts them. A new Java SPI lets an extension adjust the tool’s CSP and add page contributions. See extension response processors.
Request steering
-
Re-route to other content. A site mapping filter can change which content is rendered while the visitor’s URL stays the same - no redirect, no second request. Useful for A/B variants and personalized landing pages. See re-routing to another content.
-
Pass data down the pipeline.
setCustomLocalAttribute()passes values from a filter or a controller to response processors and the code that runs after it. Custom properties on the request object were never carried across. -
Media and page base URLs. Media and page URLs are anchored to the site’s base URL, or to the project when the request has no content, so absolute URLs are correct in previews, APIs and headless clients alike. Implicit mounting of the media APIs on every site can be turned off, and media can be served from a separate host such as a CDN. See serving media from another host.
-
API locations from vhost context. A vhost can declare where an API is served, and URL generation follows it. See API locations.
Admin events over one socket
A new admin events hub lets an application define its own topics and publish to them. Admin tools and extensions receive live updates over one shared connection instead of each opening its own. See setTopic() in the admin library.
Query fields and subtrees
-
returnsadds named index fields to each hit, so a listing that only needs a name and a path no longer costs a read per hit. The values come from the search index, so read the node where the exact value matters. Seequery()in lib-node. -
parentrestricts a query to the direct children of a node, andrecursive: trueextends it to the whole subtree. This replaces the deprecatedgetChildren()andfindChildren(); seequery()in lib-content.
In the Java API, NodeService gains list and enumerate methods for reading a subtree in path order. ListNodesResult and its recursive flag are removed; see the upgrade notes.
Exports read one version of a node
An export now reads each node at the version its scan observed. A subtree that changes while the export runs is written as it was seen, not as a mix of old and new. The batchSize parameter of exportNodes() is ignored as a result.
Bounded read-through blobstore
readThrough.cacheCapacity caps the local cache in front of a remote object store. See file blobstore configuration.
Request handling on virtual threads
threadPool.virtualThreads moves request handling to virtual threads. A request waiting on I/O - a database round trip, an outbound HTTP call, a slow client - no longer occupies a platform thread while it waits, so I/O-bound traffic stops tying up the pool. CPU-bound requests gain nothing. Selectors and acceptors stay on platform threads. See Jetty configuration.
| Virtual thread request handling is experimental and not for production use. |
Other changes
-
Java code can mark a method with
@Tracedto have it appear in XP’s internal tracing, the same mechanism the platform itself now uses. -
Cron jobs no longer fire twice within the same second, and a cron slot passing during a restart or a scheduler move is caught up instead of skipped.
-
Disposers registered by an application no longer race its own redeploy.
-
Duplicating a node tree fires the same events for the root as for the rest of the tree.
-
importNodes()no longer fails when the optionalxsltparameter is omitted. -
apiUrl()encodes itspathlike every other URL builder. -
readThrough.sizeThresholdis honored on reads, and onlysystem.admincan list exports. -
The JNA warning at startup is gone.
Deprecations
Still working, slated for removal. The upgrade notes show the replacement for each:
-
executeFunction()in lib-task - not supported on GraalJS. Submit a named task instead. -
getChildren()in lib-content andfindChildren()in lib-node - usequery()withparent. -
The
baseUrlparameter ofimageUrl(),attachmentUrl()andapiUrl()- configure the location once instead, see media base URL and API locations. -
batchSizeonexportNodes()- ignored. -
Resource.getTimestamp(), andmodifiedTimeon icons and descriptors - not a dependable measure of when a resource changed; build tools normalize jar entry timestamps for reproducible builds. -
ApplicationListenerin the Java API - trackApplicationservices instead.
XP 8
XP 8 is the largest release in 8 years. The runtime is rebuilt on a modern stack, the Universal API unifies how request handlers are written and called, and a long list of API rough edges has been cleaned up.
| This release contains Breaking changes when upgrading from XP7. We have made every effort to minimize the impact of these, but please review the full list of breaking changes and migration steps in the upgrade notes before upgrading. Several XP 7 concepts have also been renamed — see A paradigm shift in naming. |
Stack update
The XP 8 core runs on a refreshed stack, including but not limited to: Java 25, Jetty 12, and Hazelcast 5. This also includes use of virtual threads for tasks. The new stack provides better performance, stability, and security, and lays the foundation for future improvements.
Universal API
Web APIs are now first-class citizens of Enonic XP. A uniform implementation pattern can be used to implement and expose APIs across the platform, including direct exposure via the brand new /api service endpoint.
Borrowing the manifest-and-mount pattern from Kubernetes, APIs are registered with a unique name and automatically integrated with the platform’s security and IAM. A matching set of libraries and tools makes it easy to build custom APIs and call them from any context.
APIs can be exposed on custom URLs and domains via virtual host configuration, but also contextually mounted within the admin and site services, allowing for flexible API design and organization.
XP goes YAML
YAML replaces XML for all CMS schemas and app descriptors. This means content types, application definitions, ID providers, etc., are now all defined in YAML. YAML is a widely adopted format that is easier to read and write than JSON, especially for complex configurations - and it supports comments. The new YAML-based descriptors are more concise and maintainable, making life easier for developers. For the full documentation, visit the schema system documentation.
Every schema is identified by the name of the app that ships it, as <app>:<name>, such as com.example.myapp:article, in the same way as APIs, tools and extensions. Platform-provided types use the reserved names base, portal and media.
Simplified permissions
The permission model is stripped back to essentials in XP 8:
-
No more inheritance. Every node carries its own explicit ACL. To apply the same ACL across a subtree, do it in a single hierarchical apply call — the old "inherit from parent" mechanic is gone.
-
Instant cross-branch effect. Permission changes take effect on every branch a node exists in, immediately. No more publishing content just to push permissions through.
The underlying Node and Content APIs follow the same model. See Permissions for the full picture.
Companion apps
The major Enonic apps have been refreshed alongside the platform and are ready for XP 8.
- Content Studio
-
The editorial CMS interface. Migrated to the new Enonic UI design system, and continues to ship as a standalone application so it can release independently of the platform.
- Guillotine
-
Auto-generates a GraphQL API directly from your content model. Updated for XP 8’s runtime and schema changes. Note that the XP 7-era
lib-guillotineis no longer supported - it embedded the GraphQL engine in your own app, and was never a client library for the Guillotine app. - Data Toolbox
-
The developer-focused tool for inspecting repositories and nodes, and for managing dumps, snapshots, and exports. Updated for XP 8.
Admin Extensions
The Widget API has been replaced by the Extensions API, better reflecting the actual capabilities. Visible tools live in the XP menu, while extensions, you guessed it, extend them - ranging from visual widgets to API-level functionality. The new API is more flexible and powerful.
Additionally, popular extensions such as Content Studio widgets are now wrapped as web components, for complete isolation and flexibility.
Visit the Dev kit documentation for implementation details.
Content and Node Libraries refresh
Years of incremental additions left overlap in the platform Content and Node APIs. XP 8 cleans them up:
-
moveandrenamecollapse into a singlemove -
setChildOrderandreorderChildrencollapse into a singlesort -
The legacy
hasChildrencontent property is gone -
A new
patchfunction applies changes across multiple branches in one call -
Language-aware
allTextconfiguration for multilingual full-text indexing -
Removal of the
inheritsPermissionsflag in favour of explicitly applied permissions -
Sort operations also honor language-specific collation.
Prometheus metrics
Metrics are now exposed in the open OpenMetrics format - point your Prometheus, Grafana agent, or any compatible collector at the metrics endpoint to get first-class observability.
Vhost context
Vhost configuration files now support declaration of context values - project, branch, principal - co-locating routing decisions with the vhost they belong to. This may also be used to customize application behaviour on a per-vhost basis. See Virtual host context.
Server Sent Events (SSE)
XP8 also implements support for Server Sent Events (SSE) across all web services, enabling real-time streaming of data to clients without using WebSockets. This is particularly useful for building APIs and applications that require live updates, such as dashboards or notifications, but do not require the full duplex communication provided by WebSocket.
Stricter identity validation
Identity keys, content IDs, names, and descriptors now follow consistent, deterministic validation rules: lowercase-only IDs, explicit regex per key type, and length caps that match what the system actually supports. The intent is to eliminate the class of bugs that came from quietly accepting characters that broke serialization, URLs, or filesystem paths downstream. The full ruleset lives in the dev kit upgrade guide.
Security hardening
-
Authentication no longer searches for the first matching user across all ID providers. Each request resolves against the vhost’s default ID provider, or the explicitly specified one.
-
New passwords use
pbkdf2-sha512. The legacymd5andsha1hashing algorithms have been retired, including forxp.suPassword.
Smarter dumps and exports
Repositories can now be exported in full or in part - by branch and path - and repositories may be dumped and loaded individually.
Exports and dumps are written directly to ZIP archives, replacing the previous folder-based structure. The plain-file format and dry-run mode have been retired.
Quality of life
A handful of smaller-but-pleasing improvements:
-
Sessions can be persisted to the filesystem via
filestoreMode, surviving graceful restarts on standalone instances -
The admin home moved from
/admin/hometo a cleaner/admin -
HTTP function names now use the standard uppercase form:
GET,POST,PUT,DELETE -
request.localeis available in the request object -
The dump location is configurable via repository config
-
Dev mode is now enabled by default in the Enonic SDK, making it easier to get started with development and testing.
A paradigm shift in naming
XP 8 renames or reframes several familiar XP 7 concepts. Use this map when reading XP 7-era documentation, examples, or AI-generated code — the old terms no longer apply, and in some cases have taken on new meanings:
| XP 7 | XP 8 | Comment |
|---|---|---|
|
Engines (site, webapp, admin) |
The term "engine" is retired |
|
|
Controllers |
A module simply exports functions named after HTTP methods: |
|
|
HTTP Services ( |
XP 7 HTTP services are replaced by the Universal API |
|
|
JS/TS APIs ( |
The term "API" now primarily refers to web APIs. Platform JS/TS APIs are referred to as libraries |
|
|
Assets service |
The built-in asset service is replaced by a library |
|
|
Widgets |
Now part of the Admin Extensions API |
|
|
Mixins |
Reusable form definitions |
|
|
X-data |
The term "mixin" now refers to what XP 7 called x-data |
|
|
Input types and sets |
|
|
|
|
CMS resources now live in |
|
|
|
Site descriptor is now split in two, and written in YAML. |
|
|
|
Avoids confusion with content display name property |
|
|
|
|
Context-specific method names |
|
|
Discontinued |
Use the Guillotine app instead. |
| Note the double rename: the word mixin changed meaning between versions. An XP 7 mixin is an XP 8 form fragment, while XP 7 x-data is now called mixin. When working with XP 7-era material — or AI assistants trained on it — always verify which meaning applies. |
The complete map, with migration details, lives in the dev kit upgrade guide.