To get an overview about new functionality, read the Release Notes.
To learn about the necessary actions to update Livingdocs to release-2025-01
, read on.
Attention: If you skipped one or more releases, please also check the release-notes of the skipped ones.
Webinar
- Feature Webinar Recording | Passcode: v.32aM^7
- Feature Webinar Documentation
- Dev Webinar Recording | Passcode: Bc=54rh9
- Dev Webinar Slides
- Release Newsletter Subscription
System Requirements
Suggested
Name | Version |
---|---|
Node | 22 |
NPM | 10 |
Postgres | 16 |
Elasticsearch | 8.x |
OpenSearch | v2.3.0 |
Redis | 7 |
Livingdocs Server Docker Image | livingdocs/server-base:22 |
Livingdocs Editor Docker Image | livingdocs/editor-base:22 |
Browser Support | Edge >= 92, Firefox >= 90, Chrome >= 92, Safari >= 15.4, iOS Safari >= 15.4, Opera >= 78 |
Minimal
Name | Version |
---|---|
Node | 20.18 |
NPM | 10 |
Postgres | 13 |
Elasticsearch | 7.x |
OpenSearch | 1 |
Redis | 6.2 |
Livingdocs Server Docker Image | livingdocs/server-base:20:7 |
Livingdocs Editor Docker Image | livingdocs/editor-base:20:7 |
Browser Support | Edge >= 92, Firefox >= 90, Chrome >= 92, Safari >= 15.4, iOS Safari >= 15.4, Opera >= 78 |
Deployment
Before the deployment
No prior preparations are required before rolling out this release.
After the deployment
No post-deployment steps are required after rolling out this release.
Rollback
No steps are required to roll back this release.
Breaking Changes 🔥
Migrate the Postgres Database 🔥
No migrations were introduced in this release.
Drop support for Node.js 18 🔥
- 🔥 Drop Node.js
v18
. Only Node.jsv20.18.1
and newer are supported.
How to migrate your project to Node.js 22:
- Change the content of the
.nvmrc
in your project root to22
- Change the
engines.node
declaration in thepackage.json
to>=22
- Change the
Dockerfile
of the server tolivingdocs/server-base:22
- Change the
Dockerfile
of the editor tolivingdocs/editor-base:22
Server PR: Drop support for Node.js 18 Editor PR: Drop support for Node.js 18
Angular dashboard cards 🔥
As part of our ongoing migration from Angular to Vue, we have removed support for Angular dashboard cards. Please consider using the newly introduced task screens or our provided upstream task dashboard cards instead. If these do not meet your requirements, migrate your custom dashboard cards to Vue.
Editor PR: Angular dashboard cards
Dashboard type dashboard
🔥
Support for dashboards of type dashboard
has been removed. Please migrate your dashboards of type dashboard
to dashboards of type tableDashboard
.
Server PR: Dashboard type dashboard
Editor PR: Dashboard type dashboard
Comyan upload without targetMediaType
and metadata mapping 🔥
It’s no longer possible to use the Comyan integration without providing a targetMediaType
and a Comyan metadata mapping config in that media type definition. Please provide targetMediaType
in Comyan integration settings and comyanExtraction
in the media type. In the project configuration:
{
settings: {
integrations: {
comyan: {
targetMediaType: 'image'
},
mediaTypes: [
{
type: 'mediaImage',
handle: 'image',
comyanExtraction: {
mappings: []
}
}
]
}
}
}
Server PR: Comyan upload without targetMediaType
and metadata mapping
Comyan built-in postPublishHookAsync
🔥
The built-in postPublishHookAsync
used for comyan usage reporting is no longer automatically registered in the upstream code. The registration of the postPublishHookAsync
hook has to be defined in the downstream. If you are using the Comyan integration, please make sure to register the postPublishHookAsync
in your project.
To enable the same behavior as before configure the following in the downstream:
liServer.registerInitializedHook(() => {
const {reportDocumentVersion} = liServer.features.api('li-comyan')
liServer.registerPublicationServerHooks({postPublishHookAsync: reportDocumentVersion})
})
Additonally this opens up flexibility to customize when comyan usage is reported for example only registering for a certain project and execute it for desired contentTypes:
liServer.registerInitializedHook(() => {
const {reportDocumentVersion} = liServer.features.api('li-comyan')
liServer.registerPublicationHooks({
projectHandle: 'myproject',
postPublishHookAsync({documentVersion}) {
if (documentVersion.contentType !== 'article') return
return reportDocumentVersion({documentVersion})
}
})
})
Server PR: Remove Comyan usage reporting registration
Migrate to Express v5 🔥
The Livingdocs Server is now using Express v5.
- In case you have custom route declarations, please make sure they conform to the Express v5 conventions. You can find the migration guide here: https://expressjs.com/en/guide/migrating-5.html
- There’s nothing to change if there are no custom route declarations in a project.
The following changes affect the livingdocs server and maybe also downstreams:
- Wildcards in routes have a new syntax. Unsupported routes now throw an error during server start.
/designs/:name/:version/:file(*)
->/designs/:name/:version/*file
req.params.file
will result in an array with the path segments.
{
- path: '/custom/api/assets/:file(*)',
+ path: '/custom/api/assets/*file',
method: 'get',
title: 'Retrieve the files',
action: (req, res) {
const file = fileStream({
- file: req.params.file
+ file: req.params.file.join('/')
})
return pipeline(file, res)
}
}
Server PR: Migrate to Express v5
Stricter Validation of Metadata Plugin Indexing Keys 🔥
Indexing keys of metadata plugins must contain only alphabetic characters (a-z, A-Z) and dots (.). Please update all indexing keys in your custom metadata plugins that do not fulfil this requirement.
indexing: {
enabled: true,
behavior: [
{
type: 'keyword',
+ key: 'reference.id',
- key: 'reference__id',
getValue (val) { return val.reference?.id }
}
]
}
Server PR: Stricter Validation of Metadata Plugin Indexing Keys
Legacy base filter syntax in li-document-search 🔥
Base filters in metadata plugin li-document-search
no longer support the legacy filter syntax. Downstreams which define the baseFilters
using the old syntax, need to migrate them to the new Search DSL.
Server PR: Legacy base filter syntax in li-document-search
Deprecations
Sass @import
declarations are deprecated
In the Livingdocs editor, it is possible to declare an additional stylesheet. This can be done using an environment variable, such as:
CUSTOM_STYLE_PATH_AFTER=./path/to/custom.scss
When this variable is set, the editor uses the specified custom Sass/CSS file.
If your project defines such a custom stylesheet, you are likely using @import
declarations within it. However, a recent Sass update has deprecated the @import
syntax. To prevent warnings and ensure compatibility, these @import
statements need to be migrated.
Migration Guide
Follow these guidelines to migrate your @import
statements:
For files exposing variables, replace
@import
with@use
:@use '~styles/settings/defaults'; .custom-style { // Use variables from the imported file, prefixed by the file name z-index: defaults.$z-index-modal; }
This replaces the previous approach:
@import '~styles/settings/defaults'; .custom-style { z-index: $z-index-modal; }
Note: The
@use
directive automatically namespaces variables with the file name (e.g.,defaults.$variableName
), which helps avoid naming conflicts.For other cases, replace
@import
with@forward
:@forward '~styles/settings/defaults';
Use
@forward
to re-export the contents of a file without directly consuming them in the current file.
Why This Change?
The Sass team deprecated @import
because it does not enforce proper scoping, leading to potential variable and mixin conflicts in larger projects. The new directives @use
and @forward
are designed to ensure better modularity and maintainability in your stylesheets.
For more details, refer to the Sass official documentation on deprecating @import
.
Rename blacklist
and whitelist
to denylist
and allowlist
⚠️
As part of our commitment to inclusivity and clarity, we are deprecating the terms “blacklist” and “whitelist” in favor of “denylist” and “allowlist” across all configurations, APIs, and documentation. Please update your configurations and codebases to reflect this change. For example, replace blacklist with denylist and whitelist with allowlist in settings and API calls. Backward compatibility will be maintained until release-2025-07
, after which the deprecated terms will be removed.
Multi channel configuration ⚠️
Livingdocs is deprecating support for multi-channel configurations within a single project to simplify project setups and ensure a more streamlined workflow. This feature will no longer be supported starting with release-2025-07
.
If your project relies on multi-channel setups, you’ll see a deprecation message (LIDEP048
) whenver a project is loaded that has multiple channels present.
Please contact Livingdocs immediately to discuss migration strategies and alternative solutions in case you’re seeing the deprecation message.
Features
Print Diff View 🎁
In release-2024-11
we introduced the new Print Copy Flows to best support the print production workflow. To top this off print producers and editors should be able to incorporate changes of the online version into the print version easily and efficiently.
In order to achieve this the “View web changes” button which opened the history view in a new tab has been replaced with a “Compare versions” button which opens the new print diff side panel. This enables editors to preview the changes while remaining in the context of the editable print document.
No config changes are required to use this feature, it’s always available when Print Copy Flows are configured.
Brand Conditions 🎁
To support country- or brand-specific content, we are introducing a new component condition: the brands
condition. This allows downstreams to configure a set of brands, from which one or more can be selected on components to define for which brands a component should be included. This condition works alongside the already existing dateTime
condition.

To configure the new
brands
condition, downstreams need to first define a set of brands in the Project Config.brands: [ { handle: 'brand1', label: 'Example Brand 1', iconUrl: 'https://example.com/brand1.svg', isDefault: true }, { handle: 'brand2', label: 'Example Brand 2', iconUrl: 'https://example.com/brand2.svg' } ]
Then, the
brands
condition can be enabled for specific components in the content type configuration.components: [ { name: 'title', conditions: ['brands'] } ]
When requesting a document through the Composition API or any other endpoint, conditions are automatically evaluated according to the provided
componentConditions
property. If no brand is provided, the default brand will be used instead. A document can only be requested for a single brand at a time.POST {{server}}/api/beta/composition/1 { "componentConditions": { "brand": "brand2" } }
For more information, please refer to our conditional components documentation.
Visibility Mode
With the introduction of the brands
condition, we are renaming ‘Timeline Mode’ to ‘Visibility Mode’ to better reflect its new use case. Its purpose remains the same: allowing users to preview a document for a specific brand and at a specific date time.
Before release-2025-01:

release-2025-01 and after:

API
The brands
condition is supported by all API endpoints where the existing dateTime
component condition is supported:
GET /api/v1/documents/:documentId/latestPublication
GET /api/v1/documents/latestPublications
GET /api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles
GET /api/v1/publications/search
GET /api/v1/document-lists/:id
GET /api/beta/documents/:documentId/latestDraft
GET /api/beta/documents/:documentId/latestPublication
GET /api/beta/documents/latestPublications
POST /api/beta/composition/:documentId
Along with these endpoints, the related Public API methods also support the new brands
condition:
publicApi.getLatestPublication({ignoreComponentConditions, componentConditions})
publicApi.getLatestPublications({ignoreComponentConditions, componentConditions})
publicApi.getRenditions({ignoreComponentConditions, componentConditions})
publicApi.searchPublications({ignoreComponentConditions, componentConditions})
publicApi.getDocumentList({ignoreComponentConditions, componentConditions})
publicApi.getLatestDraftBeta({ignoreComponentConditions, componentConditions})
publicApi.getLatestDraftsBeta({ignoreComponentConditions, componentConditions})
Page Management: References in Base Filters
To enhance page management workflows, we are introducing support for variables in base filters of li-teaser
and li-document-search
.
For example, consider a news site where articles are categorized using a topic metadata property. Each topic has a corresponding page, which also has the same topic metadata property. Specialized teaser components based on li-teaser
and li-document-search
will then automatically use the topic from the page to display articles of the same topic, eliminating the need to manually select the topic for each teaser component through the user interface.
With variables, these components can now reference other properties to dynamically adjust their base filter, such as:
- Metadata properties of the document containing the component
- The brand for which the document is requested
Metadata Properties
For example, consider the following base filter:
baseFilters: [{key: 'metadata.topic.reference.id', termVariable: 'metadata.topic.reference.id'}]
This base filter matches all documents that share the same topic metadata property (a reference to a dedicated topic data record) which is also selected for the page in which the teaser component is currently included.
Metadata properties are accessed using the same syntax as the indexing behavior of the underlying metadata plugin. In the example above, the metadata property is of type li-document-reference
. To extract the IDs from this property, the postfix reference.id
is appended. This corresponds to the indexing behavior of li-document-reference
, specifically its key.
indexing: {
enabled: true,
behavior: [{
type: 'keyword',
key: 'reference.id',
getValue (val) { return val.reference?.id }
}]
}
Metadata properties do not need to be indexed to be referenced by a term variable (such as topic
on the topic page in this example).
If a referenced metadata property is empty, the term variable will be excluded from the query. Therefore, we recommend to always pair such terms with an additional superset term as a fallback. For example:
baseFilters: [
{key: 'contentType', term: 'article'},
// This will be excluded if metadata property topic is empty
{key: 'metadata.topic.reference.id', termVariable: 'metadata.topic.reference.id'}
]
Brand Component Conditions
In addition to metadata properties, you can reference the brand for which the document is requested using the componentConditions.brand
term variable. This enables you to load teasers relevant to a specific brand.
For example, if articles are categorized by a brand
metadata property, you can filter them using the following base filter:
baseFilters: [{key: 'metadata.brand', termVariable: 'componentConditions.brand'}]
If no brand is provided in a request, componentConditions.brand
uses the default brand as configured in the Project Config.
For more details, refer to our term variable documentation.
User needs plugin 🎁
The User Needs metadata plugin integrates the User Needs Model 2.0 into Livingdocs, allowing newsrooms to categorize articles based on audience-focused interests.
By assigning one of eight user-need categories during content creation or editing, teams can better align with audience preferences, boost engagement, and optimize content placement.
How to use User Needs in Livingdocs:
- Select them in the dashboard, in the metadata panel of the editor or in the creation-flow panel
- Edit them in the dashboard in the metadata panel
- Enable User Needs as filter in the dashboard to streamline content analysis.
For instructions on how to set it up, refer to the li-user-needs documentation.

PEIQ integration 🎁
You can now upload images directly from PEIQ via drag & drop into our system, making your workflow more efficient and straightforward.
To set it up, add the following configuration to your project settings:
// project config
{
settings: {
integrations: {
peiq: {
enabled: true,
targetMediaType: 'image',
apiEndpoint: '...',
apiToken: {
$secretRef: {
name: 'peiq-local'
}
}
}
}
}
}
To enable the import of metadata directly from PEIQ, we provide an extraction mapping feature. This allows you to define how PEIQ fields correspond to specific metadata properties:
// project config
{
mediaTypes: [
{
handle: 'image',
// ...
peiqExtraction: {
mappings: [
{field: 'name', metadataPropertyName: 'title'}
// ...
]
}
}
]
}
Document Preview Auto-Reload 🎁
By enabling auto-reloading for Document Previews, besides the existing manual reload, users can have more immediate feedback if the preview system can handle the load.
Auto-reload can be enabled by adding autoReload: {enabled: true}
to a document preview in your project config:
{
editorSettings: {
// ...
documentPreviews: [
{
// Exisiting properties
handle: 'htmlPreview',
previewFunction: 'myHtmlPreviewFunction',
icon: 'book-edit',
label: 'HTML Preview',
// New property
autoReload: {
enabled: true
}
}
]
}
}
When a Document Preview is configured for auto-reload, we don’t show the manual reload button.
Using auto-reload is not recommended for previews which are slow to render. The preview will auto-reload on every document save, which could be three seconds apart, or even more frequently when multiple users are collaborating on a document.
Real-time updates enabled by default 🎁
Real-time updates have been enabled by default. This feature is currently used to keep document content up-to-date in table dashboards, rendered includes, and document inboxes.
To opt-out of this functionality you can set pollingEnabled
and websocketsEnabled
to false
in the server config:
{
documents: {
// ...
realtimeUpdates: {
pollingEnabled: false,
websocketsEnabled: false
}
}
}
System metadata plugins 🎁
System Metadata Plugins are designed for internal use to support workflows, planning, and internal communication. They manage metadata that does not impact the document’s version history, meaning changes made through these plugins will not trigger an “unpublished change”. These plugins are strictly for internal purposes and are not relevant for content delivery, therefore they are not served through the Public API.
Therefore we are adding the following equivalents of metadata plugins to system metadata plugins:
- li-system-boolean
- li-system-date
- li-system-datetime
- li-system-integer
- li-system-enum
- li-system-target-length
Additionally the li-kordiam-schedule
metadata plugin was changed to be a system metadata plugin. This plugin facilitates internal communication between Kordiam and Livingdocs. It allows users to customize their experience by selecting the platforms and categories that they want to view in the Kordiam schedule side panel. This should not have an impact on the document’s version history.
Vulnerability Patches
We are constantly patching module vulnerabilities for the Livingdocs Server and Livingdocs Editor as module fixes are available. Below is a list of all patched vulnerabilities included in the release.
Livingdocs Server
This release we have patched the following vulnerabilities in the Livingdocs Server:
- CVE-2024-45813 patched in
find-my-way
v8.2.2 - CVE-2024-52798 patched in
path-to-regexp
v0.1.12 - CVE-2024-55565 patched in
nanoid
v3.3.8 - CVE-2025-22150 patched in
undici
v6.21.1 - [CVE-2025-27152] patched in
axios
v1.8.2
No known vulnerabilities. 🎉
Livingdocs Editor
This release we have patched the following vulnerabilities in the Livingdocs Editor:
- CVE-2024-52810 patched in
@intlify/shared
v9.14.2 - CVE-2024-55565 patched in
nanoid
v3.3.8 - CVE-2025-22150 patched in
undici
v6.21.1 - [CVE-2025-27152] patched in
axios
v1.8.2
We are aware of the following vulnerabilities in the Livingdocs Editor:
- CVE-2023-44270 vulnerability in
postcss
, it affects linters using PostCSS to parse external Cascading Style Sheets (CSS). It is not exploitable in the editor as we don’t load untrusted external CSS at build time. - CVE-2023-26116, CVE-2023-26118, CVE-2023-26117, CVE-2022-25869, CVE-2022-25844 are all AngularJS vulnerabilities that don’t have a patch available. We are working on removing all AngularJS from our code and vulnerabilities will go away when we complete the transition to Vue.js.
- CVE-2024-6783 vulnerability in
vue-template-compiler
it allows malicious users to perform XSS via prototype pollution. Editor build is always done in a trusted environment and the vulnerability is not exploitable. - CVE-2024-9506 vulnerability in
vue
, an ReDoS vulnerability exploitable through inefficient regex evaluation in parseHTML function. The issue can cause excessive CPU usage but is not exploitable in the editor as we don’t load untrusted HTML at runtime.
Patches
Here is a list of all patches after the release has been announced.
Livingdocs Server Patches
v267.1.31: fix(db): Fix scheduled components by taking over li_jsonb_patch of main branch (removing properties that don’t exist won’t throw with that)
v267.1.30: fix(li-image): Re-add the config.readOnly attribute on li-media
v267.1.29: fix(menu-tool): Log deprecation warnings in menu API
v267.1.28: fix(history): Show more than 100 revisions
v267.1.27: fix(logger): Do not try to serialize streams in pino serializer for axios
v267.1.26: fix(deps): update dependency axios from 1.7.9 to 1.8.2 [security]
v267.1.25: fix(security): Patch
undici
vulnerabilityCVE-2025-22150
to v6.21.1v267.1.24: fix(peiq): add externalid and systemname to elasticsearch
v267.1.23: fix: Throw breaking change messages
v267.1.22: fix(li-task-v2): Only show task mode in notifications if mode is configured
v267.1.21: fix(li-task-v2): Prevent notification composition failure when no modes are defined
v267.1.20: fix(webhooks): Add webhook timeout config property
v267.1.19: fix(design-version-update): Check only configured content types in
v267.1.18: fix(deps): update dependency @livingdocs/framework from 32.1.3 to v32.1.4
v267.1.17: fix(db): Correctly escape control characters in json
v267.1.16: fix(db): Fix document_revisions.metadata support in indexing-repository
v267.1.15: fix(upload): Fix video upload timeout
v267.1.14: fix(deps): update dependency @livingdocs/framework from 32.1.2 to v32.1.3
v267.1.13: chore(references): Update
manual-migrations/006-generate-references.js
to skip revision updates when there are no references on them and remove unnecessary transactionsv267.1.12: fix(print-flows): Allow content to be generated for a specific revision
v267.1.11: fix(upload): Forward image upload errors to the destination after wrapping upload streams with
limitStreamSize
v267.1.10: fix(project api limit): increase to 500
v267.1.9: chore: Fix todos check
v267.1.8: fix(vh values in designs): Added test component
v267.1.7: fix(upload): Correctly support timeouts on asset uploads
v267.1.6: fix(openid-connect): Log identity object during openid-connect authentication errors
v267.1.5: fix: Revoke user occupation also when no email transport is configured
v267.1.4: fix(media-center): Do not throw an error when the max filesize is reached
v267.1.3: fix(li-system-date): Make the new
li-system-date
andli-system-datetime
validations more strictv267.1.2: fix(deps): update dependency @livingdocs/framework from 32.1.1 to v32.1.2
v267.1.1: fix(channels): Deprecate Multi-Channel Setups (LIDEP048)
Livingdocs Editor Patches
v114.13.48: fix: Show content type label instead of content type handle in li-document-resource
v114.13.47: fix(peiq): make system name ‘peiq’ lowercase
v114.13.46: fix(dashboards): Add li-kordiam-integration to supported columns
v114.13.45: fix(toolbar): Make document dashboard active state reactive
v114.13.44: fix(deps): update dependency axios from 1.7.9 to 1.8.2 [security]
v114.13.43: fix(history): Load old designs of revisions in the history view
v114.13.42: fix(assistants): save field extractor changes after assistant finished
v114.13.41: fix(peiq): do metadata extraction when replacing an image
v114.13.40: fix(creation flow metadata form): suppress workspace injection warning
v114.13.39: fix(task-screen): Open documents with task panel open
v114.13.38: fix: scroll fixes in editor view
v114.13.37: fix: use Print instead of Druck for german print version labels
v114.13.36: fix(trackjs): sanitize Bearer, Basic, and Authorization strings in payload
v114.13.35: chore(comments): Remove tributejs dependency
v114.13.34: fix(format-popover): Do not let format popover slip behind preview panel
v114.13.33: fix: Open document inbox when in visibility mode
v114.13.32: fix(deps): update dependency @livingdocs/framework from 32.1.3 to v32.1.4
v114.13.31: fix: Close display filters in modal on click outside
v114.13.30: fix(proxy): Increase headers timeout to 1h. The livingdocs server handles the timeouts separately.
v114.13.29: fix(deps): update dependency @livingdocs/framework from 32.1.2 to v32.1.3
v114.13.28: fix(confirmation buttons): Vue
v114.13.27: fix: only resolve affected includes after deduplication was invalidated
v114.13.26: fix(display-filters): Support duplicate labels in single list display filters
v114.13.25: chore(print-flows): Change icons
v114.13.24: fix(li-table): Show table header on small screens
v114.13.23: fix(print-flows): Close print diff when metadata is opened
v114.13.22: fix(editor iframe): Overriding vh values
v114.13.21: fix(canvas): Iframe size
v114.13.20: fix(home-screen): syncUrlParams when only one search dashboard
v114.13.19: fix(proxy): Ensure we never retry requests. Despite the empty retryMethods, it still retry requests
v114.13.18: fix: Reduce wide side panel width on small screens
v114.13.17: fix(task board): correct german UI translation
v114.13.16: fix: Position formatting popover behind metadata panel
v114.13.15: fix(dialogs): Use fixed position for dialog on mobile
v114.13.14: fix(users): Include all users of admin page in csv file
v114.13.13: fix(display-filters): Re-add search and keyboard controls to li-display-filter-list-v2-single
v114.13.12: fix(visibility mode): use current component conditions to resolve includes
v114.13.11: fix: Add comment explaining why we don’t show the counter when the print preview is open
v114.13.10: fix: Fix print preview size
v114.13.9: fix: Set split pane min-width to configured start width if smaller than default
v114.13.8: fix(peiq): Register PEIQ drop handler before image drop handler
v114.13.7: fix(security): Patch vulnerability CVE-2024-52810 in
@intlify/shared
and CVE-2024-55565 innanoid
v114.13.6: fix(print-flows): Check copySource exists
v114.13.5: fix(copy): Ensure document loaded before opening panels
v114.13.4: fix: remove nzz publish control behavior
v114.13.3: fix(confirm button): Angular version
v114.13.2: fix(deps): update dependency @livingdocs/framework from 32.1.1 to v32.1.2
v114.13.1: fix(teaser-manager): Reduce include resolve requests
Icon Legend
- Breaking changes: 🔥
- Feature: 🎁