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 to XP 8.

XP 8.1

A feature release focused on the runtime beneath your apps: a preview of the JavaScript engine that replaces Nashorn, a scheduler that keeps its promises about where and when jobs run, and finer control over what a request handler may declare to the browser.

GraalJS preview

preview preview The engine that will replace Nashorn is here to try. GraalJS implements the current ECMAScript standard, well past Nashorn’s ES5.

Not for production: Nashorn remains the default and the supported engine. The choice is made per application, from its bundle manifest, so a single app can move across and back without disturbing the rest. What changes for application code - per-context module state, unconditional strict mode, disposer registration, executeFunction - is covered in the dev kit runtime documentation.

Two long-standing rough edges were settled on the way. main.ts now runs to completion before anything else in the app on that node, on either engine, which greatly simplifies initialization code. And the global namespace was brought closer to what browsers and Node expose, so more npm modules run unmodified.

Scheduler you can place and pace

Three changes make scheduled jobs predictable in a cluster:

  • Where the scheduler ticks is now a deployment decision. acceptScheduling = false excludes a node from the choice - typically the master nodes, which have to stay responsive to hold the quorum and can be modest machines precisely because they are not meant to do heavy work. The schedule, and the maintenance it submits, then runs where the machine can afford it: a data node serving no HTTP traffic, or one dedicated to background work. See scheduler configuration.

  • A job does not overlap itself. A run that overruns its interval delays the next one instead of starting it alongside; the delayed run starts once its predecessor finishes. This is best effort — a partitioned cluster can still produce an overlap.

  • One-time jobs can clean up after themselves. deleteAfterRun on a ONE_TIME schedule removes the job once it has fired, so a job created to do one thing does not linger.

  • A third schedule type. FIXED_RATE takes an ISO-8601 duration - 'PT5M' for every five minutes - for work that belongs at an interval rather than at a time of day.

Jobs can also be declared in the scheduler config file, and the scheduler’s list response now reports each job’s run state. 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 a page, its layouts, its parts and any response processor all contribute to the single emitted header, nonce included - and the header is composed when the response is flushed, so late contributions still land. A report-only companion runs alongside it, letting you enforce a settled policy while trialling a stricter one.

Requests that can be steered

  • Re-route to other content. A filter reached through a site mapping can change which content is rendered while the visitor’s address stays exactly as it was - no redirect, no second request. A/B variants and personalized landing pages become a few lines in a filter.

  • Carry your own data down the pipeline. Custom context attributes pass values from a filter or an implementation to the response processors and the code that runs after it, where inventing a request property never worked.

  • Base URLs that resolve to the right place. Media and page URLs anchor at the site’s base URL, or at the project when the request has no content anchor, so absolute URLs are correct in previews, in APIs and in headless clients alike. Implicit mounting of the media APIs on every site can be turned off, and media served from a separate host such as a CDN.

  • API locations from context attributes. A vhost may declare where an API lives, and URL generation follows it - keeping routing decisions with the vhost they belong to. See virtual host configuration.

Admin events over one socket

An admin events hub lets an application define its own topics and push to them, so admin tools and extensions receive live updates over a shared connection instead of each opening its own. See the admin library.

Ask a query for the fields you need

The returns parameter has each hit carry named index fields, so a listing that needs a name and a path no longer costs a read per hit. The values come from the search index, so they are as fresh as the index - where the exact value matters, read the node.

Query a subtree

parent restricts a query to the direct children of a node, and descendant widens it to the whole subtree beneath it. Available on the node and content libraries.

Exports read one version of a node

An export reads each node at the exact version its scan observed, so a subtree that changes while the export runs is written as it was seen rather than as a mixture.

A read-through blobstore stays within bounds

readThrough.cacheCapacity caps the local cache in front of a remote object store. See file blobstore configuration.

Request handling on virtual threads

unstable unstable threadPool.virtualThreads hands request handling to virtual threads. A request waiting on I/O — a database round trip, an outbound HTTP call, a slow client — parks its virtual thread and gives the platform worker back until the wait ends, so I/O-bound traffic stops tying up the pool. A request that computes rather than waits gains nothing. Selectors and acceptors stay on platform threads. Treat it as an experiment — not for production. See Jetty configuration.

Deprecations

Still working, slated for removal:

  • executeFunction - not supported on GraalJS. Submit a named task instead.

  • Resource.getTimestamp - not a dependable measure of when a resource changed; build tools normalize jar entry timestamps for reproducible builds.

  • content.findByParent replaced with content.query

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.

UI reloaded

XP 8 introduces a new admin UI built on the Enonic UI design system. The new UI is faster, more responsive, and provides a more consistent user experience across tools. The first tools to be migrated are the XP menu and the Dashboard. The remaining tools will be migrated in future releases.

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.

Universal API index

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.

Schemas are also now organized into namespaces. Every schema is identified as <namespace>:<name>. When shipping schemas with an app, the app name is still the default namespace - but the namespace concept decouples schemas from apps, paving the way for schemas to be authored and managed independently.

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-guillotine is 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:

  • move and rename collapse into a single move

  • setChildOrder and reorderChildren collapse into a single sort

  • The legacy hasChildren content property is gone

  • A new patch function applies changes across multiple branches in one call

  • Language-aware allText configuration for multilingual full-text indexing

  • Removal of the inheritsPermissions flag 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 legacy md5 and sha1 hashing algorithms have been retired, including for xp.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 file storeMode, surviving graceful restarts on standalone instances

  • The admin home moved from /admin/home to a cleaner /admin

  • HTTP function names now use the standard uppercase form: GET, POST, PUT, DELETE

  • request.locale is 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)

Services

The term "engine" is retired

Controllers

HTTP functions

A module simply exports functions named after HTTP methods: GET, POST, etc.

HTTP Services (/_/service/<app>/<name>)

Universal APIs

XP 7 HTTP services are replaced by the Universal API

JS/TS APIs (lib-content, lib-node, etc.)

Libraries

The term "API" now primarily refers to web APIs. Platform JS/TS APIs are referred to as libraries

Assets service

lib-asset

The built-in asset service is replaced by a library

Widgets

Admin extensions

Now part of the Admin Extensions API

Mixins

Form fragments

Reusable form definitions

X-data

Mixins

The term "mixin" now refers to what XP 7 called x-data

Input types and sets

Form items

TextLine, ItemSet, FieldSet, etc. are all form items - regardless of the value they produce

Schemas scoped by app (<app-key>:<name>)

Schemas scoped by namespace (<namespace>:<name>)

The app name is still the default namespace when shipping schemas with an app

site/ resource folder

cms/

CMS resources now live in src/main/resources/cms

site.xml descriptor

cms.yaml and site.yaml

Site descriptor is now split in two, and written in YAML.

displayName (in descriptors)

title

Avoids confusion with content display name property

delete (in JS libraries)

deleteContent, deleteProject, etc.

Context-specific method names

lib-guillotine

Discontinued

Use the Guillotine app instead. lib-guillotine embedded the GraphQL engine in your own app - it is not, and never was, a client library for the Guillotine app

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.


Contents

Contents