Release Notes > 6.6.0
Webiny 6.6.0 Changelog
See what's new in Webiny version 6.6.0
Development
Standalone Hosting: Run Webiny Without AWS (#5454
)
{/ REVIEW-PENDING @adrians5j — confirm this entry, then delete this line /}
Webiny has a new hosting type, standalone, that runs the API and Admin on a single long-running Node server backed by a SQL database. It needs no AWS account and no Pulumi. Choose it when creating a project, or pass it in non-interactive mode:
npx create-webiny-project my-project --hosting-type standaloneStandalone hosting is in alpha and is marked as such in the project setup prompt.
- SQLite or PostgreSQL. Pick the database when creating the project. The driver is set in
webiny.config.tsxwith<Infra.Sqlite>or<Infra.Postgres>, and the build leaves out the driver you don’t use. - One command for local development.
yarn devstarts the API and Admin and serves both on one URL. The port comes from thePORTenvironment variable, or the first free port from 3001. - Deployable builds.
webiny buildproduces a self-containedbuild/folder with the server entry point, worker files and a prunednode_modules, ready to copy to any server. Example GitHub Actions workflows, a Dockerfile and an nginx config are indocs/gh-actions-workflows/standalone.
- The same features as on AWS. Background tasks, scheduled actions, real-time notifications over WebSockets and streamed HTTP responses all run on the standalone server.
- Built-in sign-in. Users sign in with an email and password configured through
<SelfHostedAuth />. A forgotten password can be reset with a code sent by email, or by an administrator withyarn webiny reset-password <email>. - Licensing without the CLI. A deployed server reads the license from the
WEBINY_PROJECT_IDandWEBINY_PROJECT_API_KEYenvironment variables.
New projects run without a .env file and ship a .env.example that lists the variables you can override.
Related PRs: #5453, #5510
, #5511
, #5516
, #5527
, #5500
, #5697
, #5635
, #5715
, #5713
, #5717
, #5729
, #5718
, #5664
, #5408
, #5414
, #5915
, #5963
, #6022
, #5525
, #5547
, #5541
, #5825
, #5687
, #5926
, #5988
, #5968
, #5398
.
TypeScript 7 Compatibility (#5380
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
The build tooling has been updated for TypeScript 7, which removed the programmatic compiler API. The new approach shells out to the native tsc binary with proper cross-platform support (Windows long paths, ARM64 macOS). Several deprecated compiler options were also removed from the root config.
Remote Components Feature Flag (#5559
)
{/ REVIEW-PENDING @Pavel910 — confirm this entry, then delete this line /}
Remote Components is a new enterprise feature that allows you to create, edit, and bundle React components directly from the Admin UI, then load and render them in a Next.js frontend at runtime. The feature includes a Monaco editor with live sandbox preview, AI-powered component generation, and a Next.js runtime loader.
The remoteComponents feature flag gates the entire extension. When disabled, no GraphQL schema is registered and no admin UI is mounted.
Apollo Client Removed (#5519
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
Apollo Client and all related code have been completely removed from the repository. The Admin UI now uses a different GraphQL client internally.
Fixed Cypress Tests After TypeScript Upgrade (#5410
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
Resolved Cypress test failures introduced by the TypeScript 7 upgrade.
Project Application Server Now Included in All Templates (#5364
)
{/ REVIEW-PENDING @adrians5j — confirm this entry, then delete this line /}
Every Webiny project template now ships with a built-in application server located in /apps/projectServer. This local server hosts your Admin and Website applications during development. Previously, the server was only available in certain templates — it’s now standard across all project types, providing a consistent development experience.
Debugger Tool (#6005
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
An opt-in debugger captures data from instrumented code paths during a request. For identities with the dev-tools.debug permission, captured payloads are returned under extensions.debug in the GraphQL response.
In the Admin, Dev Tools > Debugger provides a toggle, collected count, download, and clear controls. The first instrumented call site is cms.os.list, which captures OpenSearch queries and responses around CMS entry listing.
The dev-tools.debug permission must be granted explicitly—* and dev-tools.* do not enable capture.
EventBridge Scheduler Update Fix (#6002
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The EventBridge scheduler’s update() didn’t create the schedule when it was missing, so rescheduling failed once the schedule was deleted. It now creates the schedule if needed.
GraphQL Schema Cached Across Requests (#5830
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The executable GraphQL schema is now cached and reused across requests when the schema factories produce identical output. The cache keys on type definitions plus resolver/decorator paths, and tenants with the same models share one cached entry.
Warm request times dropped from ~88ms to ~75ms locally, with GraphQLEngine.execute going from ~19ms to ~2ms per request. Heap allocation per request dropped from ~15MB to ~5MB.
Tenant Manager Permission Checks Fixed (#5848
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Permission checks in the tenant manager were awaiting getPermission() incorrectly, causing them to always pass. Any authenticated identity could create, enable, disable, and install tenants regardless of their tm.tenant permission. This is now fixed.
Website Builder Settings Permission Checks Fixed (#5848
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Permission checks for updateSettings and updateIntegrations in the Website Builder were similarly broken. Any authenticated identity could modify settings regardless of their wb.settings permission. This is now fixed.
Faster CLI Startup (#5765
,#5773
,#5779
,#5781
,#5790
,#5811
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The CLI loaded unnecessary code on every command, even webiny --help. Pulumi, AWS SDK, GraphQL libraries, and other heavy dependencies now load only when the command actually needs them. The WCP environment lookup also uses a cached REST endpoint instead of GraphQL, saving a network round trip on most commands. Combined, these changes reduce webiny --help startup time from ~2.5s to ~1.3s.
Faster Watch Mode Startup (#5781
,#5786
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
webiny watch sat silent for about 17 seconds before serving anything, spending most of that time determining whether extensions use default or named exports. This now uses a syntax-based check instead of invoking the TypeScript type checker, reducing startup from ~26s to ~12s. Additionally, watch processes now stop properly when the CLI exits via SIGTERM, preventing orphaned build workers that caused Cannot find module errors on subsequent runs.
Project License Now Applied Before Configuration Renders (#5775
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The project configuration was rendered before the WCP license was fetched, causing license-gated extensions to be silently excluded. Extensions like tenant-manager and languages that depend on license entitlements are now correctly included in the configuration after the license is known.
webiny infoLists All Deployed Environments (#5810
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Running webiny info without --env should list all deployed environments, but it only showed dev. The --env option defaulted to "dev" even when omitted, preventing the command from discovering other environments. It now lists all deployed environments when no environment is specified.
Bug Reporter (#5736
,#5746
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A built-in bug reporter is now available in every project. Press Cmd+Shift+B (or Ctrl+Shift+B), describe the issue, optionally paste a screenshot, and submit. The report includes environment information and a timeline of recent actions (route changes, clicks, GraphQL operations, errors) to help diagnose issues.
Two modes are available:
- Compose mode (default): Opens GitHub with the report pre-filled. You create the issue yourself.
- Filed mode: When configured with a GitHub token, the API creates the issue directly, including uploading screenshots.
The timeline records the last 150 events in memory. It captures labels and selectors for clicks, never field values—reports can be filed from tenants with real customer data.
An optional AI drafting extension in extensions/bugReportAi can improve the report using AI before submission. It integrates with AI Powerups settings like any other capability.
CLI Startup Performance Improvements (#5752
,#5755
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
CLI startup is now significantly faster:
- Preflight checks optimized: The system requirements and package version checks that run before every command were spawning multiple processes. Node and npm versions are now read from the environment, and the package version check caches its result against the lockfile hash. Together these save about 1.4 seconds.
- Config rendering moved in-process: The project config was rendered in a forked child process with a full DOM environment. It now renders in the CLI’s own process using a minimal React renderer. This saves about 2 seconds and makes error messages much more useful—stack traces now point to the actual location in
webiny.config.tsx.
# Before: ~4 seconds
# After: ~2 seconds
yarn webiny --helpCLI Tracing (#5741
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A new --trace flag shows where CLI time is spent:
yarn webiny <command> --traceThe report shows nested phases with durations and percentages, helping identify bottlenecks in project configuration or extension validation.
Lazy Route Matching Reduces Cold Start Cost (#5668
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Matching an incoming request used to construct every registered HTTP route — including the GraphQL engine, all CMS schemas, and the AI provider — just to read their paths and find a match. A simple OPTIONS preflight paid for the entire dependency graph and then threw it away.
Routes are now split into lightweight definitions (method, path) and their handlers. The router matches on definitions and only constructs the handler for the matched route. This noticeably reduces cold start time for requests that hit simpler endpoints.
TanStack Table Updated to V9 (#5591
)
⏳ REVIEW-PENDING
@brunozoric: confirm this entry, then delete this line.
The internal @tanstack/react-table dependency has been updated from v8 to v9. This change only affects internal Webiny packages and does not require any changes to your project code.
OpenSearch Index Migrations Now Use Dependency Injection (#5539
)
⏳ REVIEW-PENDING
@brunozoric: confirm this entry, then delete this line.
Internal OpenSearch index operations now consistently use the CmsModelOpenSearchIndexProvider pattern, ensuring the index prefix is always applied correctly. This is an internal refactoring with no changes to external APIs.
ES Module and Dependency Cleanup (#5570
,#5569
,#5562
)
⏳ REVIEW-PENDING
@brunozoric: confirm this entry, then delete this line.
Several internal packages have been refactored to remove legacy utilities and better separate AWS-specific code from server implementations. These are internal changes with no impact on project code.
Api/Route Extension Scaffold Fixed (#5457
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The Api/Route extension scaffold was generating code that no longer compiled after the Fastify-to-DI migration. The scaffold now emits the current DI route pattern using HttpRoute.createImplementation and createRegisterExtensionPlugin, matching how the framework’s own routes are implemented.
FixeduseHotkeysThrowing in Published Packages (#5771
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When using @webiny/app-admin installed from npm, every keypress in the admin threw Uncaught TypeError: is_hotkey__rspack_import_1 is not a function. This was caused by a default import of a CommonJS module that resolved differently in the monorepo versus an installed project. The import has been fixed.
Faster Admin Tailwind Build (#5799
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The admin build’s Tailwind CSS step scanned around 38,000 files under node_modules/@webiny, including declaration files, source maps, SVGs, and Markdown that can never contribute CSS classes. The scan now excludes these patterns, reducing the file count to roughly 14,000 and cutting the Tailwind PostCSS step from 2–4 seconds to about 1 second.
New-User Telemetry Was Always Reported as Returning (#5722
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Every user created since the newUser telemetry flag was introduced has been reported as returning (newUser: "no"), because the global config file was written without that key before the defaults could fill it in. The config initialisation now goes through a single code path, so the flag is set correctly for genuinely new users.
Fixed Project Creation Failing (#5472
)
⏳ REVIEW-PENDING
@brunozoric: confirm this entry, then delete this line.
Project creation could fail in both DynamoDB and DynamoDB + OpenSearch setups due to a workspace-listing dependency that no longer worked. The dependency has been replaced with Webiny’s own listWorkspaces utility.
DI-Native Handler Lifecycle and License Refresh (#5532
,#5537
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The internal event handler has been restructured into a DI-native architecture with three decoratable lifecycle abstractions: HandlerRuntime, RootContainerFactory, and ChildContainerFactory. This enables extensions to hook into handler lifecycle phases without modifying core code.
The immediate benefit: WCP license checks now refresh before the per-request registration phase, so feature-flag gates at register time see the live license state. A license change takes effect on the next request (within the 5-minute TTL) without requiring a redeploy.
Background Task Definitions Split Into Metadata and Handler (#5684
,#5692
,#5699
,#5706
,#5709
,#5710
,#5711
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Looking up a background task by ID previously built all 24 registered task definitions—including their dependencies like CMS contexts and OpenSearch clients—even though only one task was needed. Task definitions are now split into two parts:
TaskDefinitioncarries only metadata (id, title, maxIterations, etc.) and has no dependenciesTaskHandlercontainsrun()and lifecycle hooks, built only when that specific task executes
This eliminates unnecessary dependency construction during task lookups. The run() method and all lifecycle hooks (onBeforeTrigger, onDone, onError, onAbort, onMaxIterations) now receive the task definition as a parameter, allowing decorators to branch on task properties without hardcoding task IDs.
import { TaskDefinition, TaskHandler } from "webiny/api";
class MyTaskHandler implements TaskHandler.Interface<MyInput, MyOutput> {
constructor(private readonly cmsContext: CmsContext.Interface) {}
async run({ input, definition }: TaskHandler.RunParams<MyInput>) {
if (definition.maxIterations > 100) {
// Handle long-running task differently
}
// ...
}
}
export const MyTaskHandlerImpl = TaskHandler.createImplementation({
implementation: MyTaskHandler,
dependencies: [CmsContext]
});
class MyTask implements TaskDefinition.Interface<MyInput, MyOutput> {
id = "myTask";
title = "My Task";
handler = MyTaskHandlerImpl;
}HTTP Routes Now Have Names and Support Handler Decoration (#5673
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
HTTP routes now carry a name property, and request.route provides the matched route’s metadata (name, method, path) inside handlers. This enables route-specific decoration using standard DI decorators:
import { HttpRouteHandler } from "webiny/api";
export default HttpRouteHandler.createDecorator({
decorator: class implements HttpRouteHandler.Interface {
constructor(private decoratee: HttpRouteHandler.Interface) {}
async handle(request: HttpRouteHandler.Request, response: HttpRouteHandler.Response) {
if (request.route.name === "my-route-get") {
if (request.headers["x-api-key"] !== "expected") {
return response.status(401).json({ message: "Not authorized." });
}
}
return this.decoratee.handle(request, response);
}
},
dependencies: []
});Omit the name check to wrap all routes—useful for logging or timing middleware.
AI SDK Tools Split Into Definition and Handler (#5706
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
AI SDK tools followed the same pattern as background tasks: looking up available tools built all 11 tool instances and their dependencies, even though getToolSet() only reads metadata like name, description, and inputSchema.
Tools are now split into AiSdkToolDefinition (metadata only, no dependencies) and AiSdkToolHandler (the execute method and its dependencies). Handlers are built only when the AI model actually calls that specific tool during a conversation.
The AiSdkTool export has been replaced by AiSdkToolDefinition. Tools must now specify a handler class—inline execute methods are no longer supported.
GraphQL Schema Contributors Migrated to DI-Native Pattern (#5483
,#5484
,#5486
,#5492
,#5493
,#5495
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
GraphQL schema definitions across File Manager (S3 and server), Audit Logs, Workflows, Website Builder, and ACO have been migrated from legacy GraphQLSchemaPlugin to DI-native schema factories. Resolvers now declare their dependencies explicitly via builder.addResolver({ dependencies, path, resolver }) instead of service-locating them from context at runtime.
This is an internal refactor with no changes to the GraphQL API surface.
Headless CMS
Modernised Storage Operations Architecture (#5490
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
The CMS storage layer was restructured for better maintainability. Each of the 22 entry storage operations (create, update, publish, list, etc.) is now an independent abstraction registered via dependency injection, replacing a monolithic interface that bundled all operations together. This is an internal architecture improvement with no change to API behaviour.
Platform-Agnostic Search Index Tasks (#5487
,#5450
,#5431
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
Search index task handling has been restructured to support multiple database backends. The code previously tied to DynamoDB + OpenSearch has been split into base abstractions (api-search-index) with dedicated implementations for OpenSearch (api-search-index-os) and DynamoDB + OpenSearch (api-search-index-ddb-os). This enables the upcoming Postgres + OpenSearch support.
CMS Entry Collaboration With Threaded Comments (#5473
)
{/ REVIEW-PENDING @SvenAlHamad — confirm this entry, then delete this line /}
You can now add threaded comments to Headless CMS entries, anchored to the entire entry or a specific field. Comments support replies, resolve/reopen states, editing, @mentions, and soft-delete. A new Comments toggle in the entry editor header opens an animated side panel with per-field comment markers.
Key capabilities:
- Click a field’s comment marker to filter the panel to that field’s threads
- Copy shareable deep-links to specific threads via “Copy link to thread”
- URL query parameters (
commentThread/commentField) open the panel and scroll to the referenced thread
Notifications Inbox for Comments and Workflows (#5473
)
{/ REVIEW-PENDING @SvenAlHamad — confirm this entry, then delete this line /}
A per-user notifications inbox is now available in the Admin UI. A bell icon in the top bar shows an unread badge and opens a slide-in panel with Inbox/Archive tabs, an unread-only filter, and time-grouped notification items.
Notifications are triggered by:
- Comments — when you’re @mentioned in a comment or someone replies to your thread
- Advanced Publishing Workflow — when your entry is approved or rejected
Each notification deep-links to the relevant CMS entry and comment thread.
Extract OpenSearch Sync to a Dedicated Package (#5413
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
The OpenSearch synchronization logic has been extracted from the DynamoDB-specific package into its own standalone module. This architectural change enables reuse of the sync mechanism across different storage backends.
CMS Bulk Actions Now Support Multiple Deployment Targets (#5529
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
CMS bulk actions have been restructured to support both serverless (AWS) and traditional server deployments, following the same pattern used by other Webiny packages.
Postgres Storage Operations Research and Design (#5402
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
This release includes internal research and design documentation for adding Postgres + OpenSearch storage operations to the Headless CMS. No code changes are included — this is foundational work exploring a hybrid architecture where Postgres serves as the source of truth for writes and point lookups, while OpenSearch handles all search, filter, and sort operations.
Key architectural decisions documented:
- Table-per-model structure with shared tables using a tenant column
- System fields stored as real columns, user field values in a single
valuesJSONB column - WAL logical replication for Postgres → OpenSearch synchronisation
- Upsert pattern for CRUD operations
This is research-only — no production code or migration paths are included in this release.
SQL Storage Now Supports Multi-Tenancy (#5812
)
⏳ REVIEW-PENDING
@brunozoric: confirm this entry, then delete this line.
The SQL CMS storage (@webiny/api-headless-cms-sql) previously used single-column primary keys, which meant the same model, group or entry ID could not exist in multiple tenants. All keys now include the tenant, and every query is scoped accordingly. This also fixes several cross-tenant data leaks where operations could inadvertently read or modify another tenant’s records.
No migration is provided. If you are using the unreleased SQL storage in development, drop and recreate your database.
Birthday Picker for Date Fields (#6033
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Date-only fields now support a step-by-step Birthday Picker renderer. The field displays as a DD / MM / YYYY bar; clicking it opens a card that walks through day, month, and year grids with the newest year first.
The dateGte and dateLte validators now accept dates relative to today using expressions like today-18y. The picker reads these limits and only offers dates the field accepts. The model editor’s Validators tab lets you choose between “Fixed date” or “Relative to today” for date-only fields.
Reference Autocomplete Search Improvements (#6019
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The reference field autocomplete couldn’t find some entries by name. Two issues caused this: the API returned the newest matches rather than the best title matches, and the dropdown re-filtered results by fuzzy-matching against entry IDs.
Search results are now ordered by title match quality—exact match first, then prefix, then contains—before being cut to the limit. The dropdown no longer filters server results, so entries matched on fields other than the title still appear.
Readable Values in Accordion Item Titles (#6008
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Object list fields rendered as accordions now show readable values in item titles. Text fields with predefined values display the option label instead of the stored value (e.g., “Personal Training” instead of personal-training). Reference fields show the referenced entry’s title instead of falling back to “Item #1”.
New Entries Now Created in the Open Folder (#6015
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Creating a new CMS entry from inside a folder incorrectly saved it to the root folder. The form now passes the currently open folder to the create mutation, including entries created through the wizard.
Fixed Content Entry Saves Overwriting the Wrong Entry (#5982
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Saving an entry could write values to a different entry if you opened entry B while entry A was still validating. The save now stops if the form or model changed during async validation. “Save & Publish” could also publish the wrong entry under the same race condition — this is now prevented.
Fixed Reference Field Search Returning Stale Results (#5982
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The reference field autocomplete kept whichever search response arrived last. A slow response for a shorter query could replace the results for the current search term, causing matching entries to disappear. Only the latest search request now writes results.
Fixed Live Preview Loading Incorrect Domain (#5982
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The CMS live preview loaded localhost:3000 until frontend settings arrived, and hung if they failed to load. A personal preview-domain override set in Website Builder also silently applied to the CMS. The preview now waits for the domain and shows an error with a Retry option when it fails. The override menu is now a shared component used by both the CMS address bar and the Website Builder editor.
Entry Collaboration and Notifications Inbox (#5955
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
This feature requires a licence that includes collaboration capabilities.
You can now add comments to CMS entries, either on the entry as a whole or on specific fields. Comments support threads, replies, and resolution states. A notifications inbox in the Admin header shows replies and workflow events. Clicking a notification opens the entry and scrolls to the relevant field.
For fields inside collapsed dynamic zones or accordions, clicking “jump to field” automatically expands the necessary containers and highlights the target field.
Duplicate Entry Action (#5937
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A new “Duplicate” action is available in the CMS entries table. It creates a copy of the selected entry with the same values. The GraphQL API exposes a corresponding duplicate<Model> mutation.
Private Models Can Opt Out of Lifecycle Events (#5937
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Private models can now disable entry lifecycle events by setting lifecycleEvents: false in the model builder. This prevents Cms/Entry events from being published for entries in those models, which is useful for internal data that doesn’t need external integrations listening to changes.
Stable Metadata on Publish and Unchanged Saves (#5932
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Publishing, republishing, or unpublishing an entry no longer updates savedOn, modifiedOn, savedBy, or modifiedBy. These fields now change only when the entry’s content actually changes. This fixes issues where list order would shift unexpectedly after publish operations.
Reference Field Values in Live Preview Paths (#5954
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A model’s previewPath can now read values from referenced entries. For example, /{values.location.slug}/{values.slug} resolves the slug field from the referenced location entry. The live preview address bar shows the resolved path instead of raw placeholders.
Reference Field Filtering in Advanced Search (#5947
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Advanced search filters now support reference fields. When you select a ref field in a filter, an entry picker appears so you can choose which referenced entry to filter by.
Reference Autocomplete Keeps Search Results (#5954
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When picking an entry from search results in a reference field autocomplete, the selection now persists correctly. Previously, entries found via search (beyond the first 10 default options) would be lost after selection.
Fields Projection in CMS SDK (#5946
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The getEntry and listEntries methods in cms-sdk now accept a fields parameter to request only specific fields, including nested fields:
const result = await sdk.cms.getEntry({
model: "article",
id: "abc123",
fields: ["title", "author.name"]
});Entries and Models No Longer Return Stale Data After Writes (#5914
,#5912
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Two caching issues could cause the API to return outdated CMS data:
DynamoDB entries were cached across requests. The DataLoader that fetches entries was registered as a singleton on the root container, so it persisted across Lambda invocations. A write on one instance didn’t clear the cache on others, causing stale reads. The DataLoader is now registered per request.
Models were filtered by the first caller’s permissions. The model cache was built once per request but filtered by whoever triggered it. If an anonymous request ran first, later requests running under
withoutAuthorization(like schema composition) saw a filtered list. Model providers now return all tenant models, and access control is applied by the use cases that consume them.
Cross-Tenant Data Leaks Fixed (#5888
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Code that switched tenants with withTenant() while holding a model reference could read or write data in the wrong tenant. This affected scheduled publishing on sub-tenants. All entry, model, and group repositories now stamp the current tenant onto their inputs before any storage operation.
Stable_idAdded to Object and Dynamic-Zone Values (#5909
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Every object and dynamic-zone value now carries a stable _id field. IDs are generated on create, preserved through updates, and available in both read and manage GraphQL APIs. This lets features like comments and annotations reference a specific item in a list, even after reordering.
{
getProduct(revision: "abc123") {
variants {
_id
sku
}
}
}Existing entries return _id: null until they’re saved again.
Revision Notes and Deletion Fixes Ported From 6.5.0 (#5913
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Several entry management improvements from 6.5.0 are now on the main branch:
- A revisions drawer showing status (Draft, Published, Previously published), creation info, and the ability to add or edit notes
- A warning banner when viewing an older revision, with a link to the latest
- Deleting the published revision now correctly clears the live pointer
- The pattern field validator no longer crashes on
nullflags
Fixed$.Rule Targets Inside List Items (#5865
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Condition rules using $. paths inside list items now resolve correctly. Previously, these paths weren’t being evaluated properly within nested list contexts.
Code-Defined Datetime Fields Default to Timezone-Aware Format (#5865
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When using fields.datetime() without specifying a subtype in code-defined models, the field now defaults to dateTimeWithTimezone. Previously, the GraphQL, storage, and admin layers each assumed different formats, causing inconsistent behaviour.
Rejected Save Errors Now Shown in the Entry Form (#5865
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Entry save errors (CmsEntryError) are now properly displayed in the entry form. Previously, certain API rejection errors were silently swallowed.
Object and Dynamic Zone Fields Laid Out by Stored Layout (#5865
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Object and dynamic zone fields now respect their stored layout configuration instead of using a default layout.
Dynamic Zone Template Picker Restored (#5854
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The search and list view in the dynamic zone template picker are working again. Template descriptions are now shown where available, and keyboard users can navigate and select templates.
"Create From Revision" Works With Dynamic Zones (#5854
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Creating a new revision from an existing one now correctly handles dynamic zone values. Previously, the values were sent in the form’s internal shape (_templateId with a flat object) instead of the API’s expected { [gqlTypeName]: {...} } format.
Fixed Bulk Action Entry Version IDs (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Bulk actions now preserve the version in entry IDs. Previously, version information was being stripped, causing operations to target the wrong revision.
Content Model Group Picker Restored (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The content model group selection now works as a dropdown list again, after a regression broke the picker.
AI-Powered Image Enrichment Now Requires a Vision Model (#5807
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Image enrichment previously fell back to the Standard model when no Vision model was configured. This caused failures when the Standard model couldn’t process images, with unclear error messages about image input. The Vision role now requires an explicit model assignment — enrichment fails immediately with a clear message naming the setting to configure. Fast continues to fall back to Standard when unset. Existing projects upgrading from 6.4.x will have their Vision model automatically populated from legacy provider settings.
Image Enrichment Skips Quietly When Disabled (#5809
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Turning off Image enrichment under Settings → AI Power-Ups → Capabilities previously logged errors and marked background tasks as failed on every upload. A deliberately disabled setting is not a failure. When enrichment is switched off, the task now completes silently without downloading the image. Genuine misconfigurations (missing model, deleted connection) still fail with an error.
Mark Fields as Disabled (#5719
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
CMS fields can now be marked as disabled. A disabled field renders in the entry form with its value visible but not editable. This is useful for values that something other than the editor owns—an external ID, a generated slug, or a field that a sync job writes over the API.
From a code-defined model:
builder
.public({ modelId: "catalogueItem", name: "Catalogue Item" })
.fields(fields => ({
externalId: fields
.text()
.label("External ID")
.help("Set by the catalogue sync, not editable here.")
.disabled(),
name: fields.text().label("Name"),
price: fields.number().label("Price")
}));You can also enable the Disabled switch on the General tab of the field settings drawer for models built in the model editor.
Disabling an object field automatically disables all fields inside it. The disabled state only affects the Admin UI—the API still accepts writes to disabled fields, so integrations can continue to update them.
Audit Logs Now Record CMS Entry Changes (#5762
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Audit logs for CMS entries stopped being recorded after version 6.1.0. The Audit Logs page in the Admin would load but always show an empty list. This was caused by a missing context registration that prevented the audit log handlers from writing. CMS entry creation, updates, and other changes are now properly recorded again.
Fixed Filtering and Sorting for Field IDs With Underscores (#5700
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Fields with underscores in their IDs (such as on_sale) could not be filtered or sorted correctly. A filter like on_sale_contains was attributed to a non-existent field on, causing the query to fail. Sorting was worse — an unmatched directive was silently dropped, so the query ran unsorted while the caller believed it was sorted. Both mappers now correctly handle underscored field IDs.
Scheduled Publishing Now Works on AWS (#5657
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Scheduled publishing was silently broken on AWS. Entries set to publish at a specific time would stay in Draft with a “Scheduled” badge, and nothing would happen. The underlying schedule was created correctly in EventBridge and fired at the right time, but the Lambda dispatch layer rejected the incoming event because the scheduler’s event handler was never wired into the production composition root. Fixed — scheduled publishes now fire as expected.
Model Providers Replace Synchronous Resolution Hooks (#5632
,#5633
,#5634
,#5636
,#5638
,#5639
,#5645
,#5650
,#5651
,#5654
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A significant internal refactor removes the RequestContextInitializer hook system that previously ran after authentication to inject pre-resolved CMS models and other request-scoped values into the dependency container. The hook existed because DI resolution is synchronous while model loading is async — so a hook deposited the resolved value for later consumers.
That pattern forced every route to pay for model resolution whether it needed those models or not, and it created ordering constraints between hooks that were documented in comments but enforced only by convention.
The new approach uses providers — lightweight wrappers that defer the async work until a consumer actually needs the value:
class SomeRepository {
constructor(private pageModelProvider: PageModelProvider.Interface) {}
async execute() {
const pageModel = await this.pageModelProvider.get();
// ...
}
}This affects FileModel, FolderModel, AcoFolderModel, and all four Website Builder models (Redirect, Variant, Experiment, Page). The scheduler service and the sharp image transform handler follow the same pattern.
If you were injecting any of these model abstractions directly (e.g., FileModel, PageModel), you now need to inject the corresponding provider and call .get() inside your async method.
Code-Defined Folder-Level Permissions (#5620
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Folder-level permissions can now be defined in code alongside roles and teams, instead of only through the Admin UI:
import { FlpFactory } from "webiny/api/aco/flp";
class MyFolderPermissionsImpl implements FlpFactory.Interface {
async execute(): FlpFactory.Return {
return [
{
type: FlpFactory.FolderType.Cms.Entries("article"),
path: "/marketing/*",
permissions: [{ team: "content-team", level: "editor" }]
}
];
}
}
export default FlpFactory.createImplementation({
implementation: MyFolderPermissionsImpl,
dependencies: []
});Code-defined permissions appear in the Admin UI as locked entries that cannot be edited there. A no-access rule cannot be overridden and is inherited down the folder subtree. Full-access users bypass code-defined permissions the same way they bypass stored ones.
FlpFactory.FolderType builds the folder types that ship with Webiny. For a custom folder type registered by your own app, pass the type string directly.
Auto-Focus Field Settings on Open (#5479
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When opening the Field Settings drawer in the content model editor, the Label input is now automatically focused, saving you a click.
Full-Text Search Fixes for Nested and Mixed-Type Fields (#6009
,#6003
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Full-text search on “Searchable JSON” fields with nested objects or mixed types (dates, numbers, booleans alongside strings) could fail the entire query or miss nested values. The underlying Elasticsearch query now uses lenient: true and builds field paths from parent objects, so searches work across arbitrarily nested structures. The contains filter also searches recursively through arrays and objects at any depth.
Unknown Dynamic Zone Templates No Longer Break Entry Reads (#6009
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Reading an entry whose dynamic zone value referenced a template that had since been removed from the model threw UNKNOWN_TEMPLATE and broke the whole response. The value is now skipped with a warning, and the rest of the entry loads normally.
Improved Error Handling for Failed Result Checks (#6003
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Several internal operations read .value on a Result without checking whether it succeeded, masking the actual error (a permission issue, a storage failure) with a generic message. All affected call sites now check isFail() first and surface the original error or handle it appropriately.
Removed theHeadlessCmsFacade (#5940
,#5951
,#5962
,#5965
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The HeadlessCms facade and TasksCrud adapter have been removed. Code that previously accessed CMS operations through the facade should now use the individual use cases directly:
import { GetModelUseCase, ListLatestEntriesUseCase } from "webiny/api";
// Before: context.cms.getModel(id)
// After:
const result = await container.resolve(GetModelUseCase).execute({ modelId });Background task operations have been similarly refactored—GetTaskUseCase and ListTasksUseCase now return Result types instead of throwing or returning null.
Infrastructure
Replaced VulnerabledecompressLibrary (#5521
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
The unmaintained decompress package (last published 2018) has been replaced with adm-zip, which is actively maintained, has zero dependencies, and includes built-in zip-slip protection against path traversal attacks.
Fixed Destroy Failures With GuardDuty Malware Protection (#5475
)
{/ REVIEW-PENDING @adrians5j — confirm this entry, then delete this line /}
Destroying a Webiny project failed when a GuardDuty Malware Protection Plan existed (File Manager Threat Detection), because the deploy role lacked EventBridge permissions for GuardDuty-managed rules. The deploy policy now includes the necessary permissions scoped via the events:ManagedBy condition key.
Background Tasks Split for Multi-Environment Support (#5370
)
{/ REVIEW-PENDING @brunozoric — confirm this entry, then delete this line /}
The background tasks package has been split into core, aws, and server variants, enabling background task functionality across different deployment environments (AWS Lambda and traditional servers).
Sub-Tenant Assets Now Served Correctly (#5889
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Assets uploaded to a sub-tenant returned a 404 from the Asset Delivery URL, even though they appeared in the File Manager. The asset delivery route now runs in the context of the tenant that owns the asset, so files from any tenant are served correctly. Note that assets from disabled tenants are no longer served.
WebSocket Connections Now Reconnect Automatically (#5869
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
WebSocket connections that dropped unexpectedly, such as from network issues, often stayed down until the browser tab regained focus. This caused results from background tasks like remote component generation to be lost. Connections now reconnect automatically after any unexpected close, with exponential backoff up to 30 seconds. A heartbeat every 5 minutes also keeps connections alive, preventing API Gateway’s 10-minute idle timeout.
Feature Flags Now Correctly Disable Licensed Features in the API (#5866
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Setting <Project.FeatureFlags features={{ auditLogs: false }} /> had no effect on the API — licensed features like audit logs and record locking still ran. Build parameters are now registered before features, so the flags are available when each feature decides whether to enable itself.
VPC Disabled Flag Now Respected (#6002
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Setting <Infra.Vpc enabled={false} /> in production was ignored, still creating a VPC. The flag is now respected.
CloudFront Minimum Protocol Version (#6002
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Custom domains can now specify a minimumProtocolVersion for CloudFront.
Fixed Background Task Cleanup Missing Records (#5964
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When cleaning up a background task with many children or logs, only the first page of records was deleted. Everything beyond the first page was orphaned. The cleanup now pages through all records.
Fixed Folder Permission Task Failures Not Logged (#5983
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When a folder’s permission task failed to trigger, the failure was silently dropped. These failures are now logged with the folder ID for easier debugging.
Folder Change Notifications Sent After Permissions Applied (#5976
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Folder create and update notifications are now sent after the folder-level permission records are written, not before. This prevents the admin from briefly showing stale permissions after a folder change.
Faster GraphQL Schema Composition (#5916
,#5924
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The GraphQL schema is now cached based on factory keys, so it’s only recomposed when something actually changes. Previously, all 50+ schema factories ran on every request even when the cached schema was valid. Warm request latency for simple queries dropped from ~30ms to ~25ms.
Identity Provider Keys Cached Across Requests (#5934
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Signing keys from identity providers (Cognito) are now cached across Lambda invocations instead of being fetched on every authenticated request. This eliminates two HTTPS calls per request, roughly halving warm request latency for authenticated admin users.
Key rotation is handled automatically: if a token is signed with an unknown key, the cache refreshes once and retries. Keys older than 10 minutes are refetched to handle revocation.
CMS Storage Operations Registered per Request (#5933
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Extensions that decorate CMS storage operations (e.g. custom OpenSearch index logic) now work correctly. Previously, decorators registered in extensions were silently ignored because storage operations were registered in the root container.
If you have a deployed project with an extension that decorates CmsModelOpenSearchIndex and changes index names, this fix will cause that decorator to start applying. Verify your OpenSearch indexes before upgrading.
Audit Logs Write to the Correct Table (#5950
)
⏳ REVIEW-PENDING
@SvenAlHamad: confirm this entry, then delete this line.
Audit logs were being written to the main DynamoDB table instead of the dedicated audit logs table. This caused writes to fail because the tables have incompatible index schemas. Audit logs now write to DB_TABLE_AUDIT_LOGS as intended.
Cold Start Performance Improvements (#5899
,#5900
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Two changes reduce cold-start latency:
- Schema building is faster. The GraphQL engine now attaches resolvers in place instead of rebuilding the schema, saving ~120ms on a 1024 MB Lambda.
- Encryption key derivation is cached. The AES key was derived with scrypt on every request. It’s now derived once per process and reused.
Together, authenticated warm requests dropped from ~230ms to ~57ms at p50.
Background Task Iteration Timeout Respects Task Budget (#5846
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Each background task iteration request now uses the task’s remaining time budget as its timeout, instead of a fixed 60-second limit. This prevents long-running iterations (like image enrichment with AI retries) from being cut off while the task still has time remaining.
AI Streaming Route Handles Provider Errors (#5828
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The AI image enrichment streaming route now properly handles provider errors. Previously, streamText passed errors to onError instead of throwing, so the route would complete with empty results marked as successful.
Faster GraphQL Lambda Cold Starts (#5802
,#5808
,#5822
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Warm GraphQL requests on Lambda were several times slower than in 6.4.x — a simple { __typename } query took 350-900ms versus 35-110ms previously. The slowdown came from rebuilding the GraphQL schema on every request using mergeSchemas. Background tasks, record locking, and audit logs have been refactored to register at startup instead of building contextual schemas per request. With no contextual schemas left, mergeSchemas is skipped entirely, bringing warm request times back down.
SSE Responses Now Prevent Caching (#5737
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Server-sent event (SSE) responses from the AI streaming endpoints now include no-store in their cache-control headers, preventing any intermediary from storing these per-user responses. Previously the headers only prevented revalidation, which technically permitted storage.
Fixed Streaming Route Task Scheduling (#5694
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Background tasks scheduled from streaming routes (such as /stream/*) were being silently dropped. The streaming handler was missing the task dispatcher registration, so TaskService.trigger() would fail without any error being surfaced. This affected File Manager’s re-enrich route and the AI chat routes.
Fixed Team Role Resolution (#5685
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When creating or updating a team, role slugs passed to team.roles matched nothing because the field expects role IDs. The team would be created and appear correct in the admin UI, but grant no permissions. Both slugs and IDs are now accepted and resolved to the correct ID before storage.
VPC Endpoint Permissions Added to the CloudFormation Template (#5646
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Projects using the useVpcEndpoints VPC option would fail to deploy because the CloudFormation template was missing the required IAM permissions for creating and managing VPC endpoints. Fixed — the template now grants ec2:CreateVpcEndpoint, ec2:ModifyVpcEndpoint, ec2:DeleteVpcEndpoints, ec2:ModifyVpcAttribute, and ec2:DescribeVpcEndpoints.
Streaming API Permissions Added to the CloudFormation Template (#5637
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The streaming GraphQL endpoint requires Lambda Function URLs and CloudFront origin access controls, neither of which existed in earlier Webiny versions. The CloudFormation template now includes the necessary permissions for cloudfront:*OriginAccessControl*, cloudfront:*OriginRequestPolicy*, and lambda:*FunctionUrlConfig*.
API-Key Authentication Fixed (#5504
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
API-key requests were silently authenticating as anonymous because identity was established before the tenant context was set. The API-key authenticator needs the tenant to look up the key, so it returned null on every request. This affected any API-key consumer (including the Next.js starter) while Cognito/JWT auth in Admin appeared to work fine. The tenant context is now established before identity, and API-key failures are logged for debugging.
Private Files Feature Gate Fixed (#5523
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The private files feature was incorrectly gated at module registration time, before the WCP license was loaded. This meant the feature was always disabled regardless of your license. Feature registration is now unconditional, with the license check happening at request time when the license is available.
Renamed--flavourto--hosting-type(#5456
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The CLI option --flavour has been renamed to --hosting-type and the environment variable WEBINY_FLAVOUR is now WEBINY_HOSTING_TYPE. This change affects create-webiny-project and internal tooling — generated projects are unaffected.
Renamed@webiny/handler-graphqlto@webiny/api-graphql(#5466
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The package @webiny/handler-graphql has been renamed to @webiny/api-graphql to align with Webiny’s api-* naming convention. Update your imports:
// Before
import { ... } from "@webiny/handler-graphql";
// After
import { ... } from "@webiny/api-graphql";Removed@webiny/handler-awsPackage (#5465
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The @webiny/handler-aws package has been deleted as it had no active consumers after the event-handler migration. If you were importing LambdaContext from this package, use Context from @webiny/aws-sdk/types instead.
Cognito Provider Registered Only Through(#5981
,#5980
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The Cognito identity provider was registered twice—once in the root container and again per request—causing every request to build two providers. The root registration has been removed; Cognito is now wired only when <Cognito/> is present in your webiny.config.tsx. Projects created from the official templates already include it.
OpenSearch Registries Now Include Extension Operators and Indexes (#5980
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Custom OpenSearch query operators or indexes registered by extensions were silently ignored, because the registries were root singletons that never saw per-request registrations. Both registries are now scoped per request, so extension-registered operators and indexes appear alongside the built-ins.
Upgraded to@webiny/di2.0 (#5969
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The dependency injection library has been upgraded from 1.x to 2.0. Two identity providers (CognitoIdentityProvider and SelfHostedJwtIdentityProvider) have been updated to use container-scoped registration instead of singleton-scoped, ensuring they correctly receive per-request configuration like custom identity providers from extensions (e.g., Entra ID) and self-hosted signing secrets.
Breaking Changes
Feature Flags Replace WCP as Primary Feature Availability System (#5559
)
{/ REVIEW-PENDING @Pavel910 — confirm this entry, then delete this line /}
Feature flags are now the primary authority for feature availability, replacing the previous WCP-based system. The license acts as the gate, while configuration in webiny.config.tsx acts as the switch within that gate. In the Admin UI, useFeatureFlags() replaces useWcp(), and FeatureFlag.CanUse* components replace Wcp.CanUse* components.
The decision flow is:
- No license → feature disabled
- License blocks the flag → feature disabled (config ignored)
- License allows + config explicitly false → feature disabled
- License allows + config unset → feature enabled (license is authority)
- Not license-governed + license exists → config decides
Use the new isEnabled("name") API with dot-path support for checking feature availability:
import { useFeatureFlags } from "webiny/admin";
const { isEnabled } = useFeatureFlags();
// Check if a feature is enabled
if (isEnabled("aiPowerups.cms.entryGeneration")) {
// Feature is available
}Website Builder
Tags, DateTime and RadioGroup Inputs Now Work in the Component Editor (#5891
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Components using createTagsInput, createDateInput or createRadioInput from the Website Builder SDK previously showed “Missing renderer” errors in the editor sidebar. All three input types now render correctly: tags accept multiple values, date-time opens a picker and saves an ISO string, and radio groups display the configured options.
List Inputs Now Preserve All Default Values (#5892
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
A list input without child fields, such as a tags list in component defaults, previously kept only its last item. For example, features: ["Autocomplete", "Limited AI integration"] became just "Limited AI integration". All items are now preserved when an element is created from defaults or bindings.
Component Helpers Now Work in the Browser Preview (#5890
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
A remote component that defines helper functions next to its default export, such as function CheckIcon() {}, now renders correctly in the component editor preview. Previously the preview crashed with ReferenceError: CheckIcon is not defined because the browser bundler dropped all declarations except the default export.
Editor Preview Stays in Sync When Undoing Input Changes (#5872
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Typing in an element’s input and then pressing Undo left the preview showing the typed value while the input reverted. This happened because preview patches were computed against committed values rather than what the preview was actually showing. The editor now tracks what each preview displays, so reverting or deleting characters updates the preview correctly.
Nested Object Inputs Now Render Correctly (#5871
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
A component manifest with nested object inputs, such as a testimonials list containing an author object with its own fields, showed “Missing renderer” for every nested field. The browser bundler now transforms inputs at any depth, not just the first two levels. Components saved before this fix will be corrected automatically when re-bundled.
Grid Background Added to Editor Preview (#5873
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
The component editor preview now displays a subtle grid background behind the canvas, making element boundaries easier to see while editing.
Page Lifecycle Events Can Now Modify Pages (#6032
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Page “before” event handlers (page.beforePublish, page.beforeCreateRevisionFrom, etc.) can now modify the page that gets saved. Previously, changes made in these handlers were ignored. The events now follow the same convention as CMS and File Manager: the payload carries the page that will be saved and an original where there is a previous version.
Delete Page Revision Mutation (#6004
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Added WbMutation.deletePageRevision(id) to the GraphQL API. The mutation checks permissions, publishes lifecycle events, and delegates to the CMS delete revision use case. The admin app’s revision drawer now properly supports deleting revisions with confirmation dialogs.
Page Revisions Cache Updates (#6004
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Creating, publishing, unpublishing, and deleting page revisions now update the revisions cache. Publishing also marks the previously published revision as unpublished. The revisions list is now ordered by version number instead of savedOn, so editing an older revision no longer moves it above newer ones.
Workflow-Approved Pages Are No Longer Read-Only (#6004
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Pages with an approved workflow state are no longer forced into read-only mode. The editor becomes writable again once a review is approved.
Full-Text Search for Page Properties (#6002
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Full-text search now matches searchable JSON fields like the page model’s properties. On DynamoDB + OpenSearch, page search previously found nothing because these fields weren’t included in the query.
Prevent Deletion of Non-Empty Folders (#5943
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Attempting to delete a Website Builder folder that still contains pages or redirects now fails with a clear error. Empty folders can still be deleted.
Asset Values Readable by 6.4 Frontends (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Asset details now include MIME types and image dimensions in a format that 6.4 frontends can read, ensuring backward compatibility during upgrades.
Component Generation Now Uses AI Capabilities (#5805
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Generating and refining Website Builder components using AI was broken for projects configured after 6.5.0. The feature read from a legacy settings structure that no longer exists, showing “No AI provider configured” even with a model set up. Component generation now resolves through the wb.generateComponent capability, which means you can configure it under Settings → AI Power-Ups alongside other AI features.
Custom Routes Are Reachable Again (#5671
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Custom HTTP routes defined via <Api.Route /> in your project were silently broken — they deployed successfully, API Gateway forwarded requests to the Lambda, but the internal router found nothing and returned a 404 with no log output. The route handler’s wiring was missing after a recent internal refactor. Fixed, and both path syntaxes (:orderId and {orderId}) now work interchangeably:
<Api.Route method={"POST"} path={"/my-route"} src={"/extensions/MyRoute.ts"} />Preview Domain Tooltip (#5479
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The globe icon in the page preview address bar now shows a “Change preview domain” tooltip, matching the pattern used by other toolbar icons.
Audit Logs for Page and Redirect Folder Deletions (#6009
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Deleting a Website Builder page folder or redirect folder now records an audit-log entry. Previously these actions were silently untracked.
Schedule Action Hidden Without Publish Permissions (#6009
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The schedule-publish menu item in the page editor was visible to users who lacked both publish and unpublish permissions. It is now hidden for those users, matching the behaviour of the pages list.
Admin
AI Power-Ups Settings Can Be Saved After Model Retirement (#5867
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Saving AI Power-Ups settings failed with “Model is not available” when the stored settings referenced a model that had been removed from the WCP catalog. The legacy providers section no longer validates model IDs against the catalog, so settings can be saved regardless of which models were previously configured.
AI Temperature Only Sent to Models That Support It (#5868
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
Several AI models reject the temperature parameter outright, causing features like CMS revision comparison and page translation to fail. The Ai.generateText() and Ai.streamText() methods now check whether the model’s catalog entry declares temperature support and omit the parameter if not. Callers can continue passing temperature and let the SDK decide.
Split View Sizing Fixed (#5993
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Split panel minimum sizes were being interpreted as pixels instead of percentages, allowing panels to be dragged down to almost nothing. The CMS entry form also got too narrow when comments were open. Split views now use percentage-based sizing with proper minimums, and the entry form has a 420px minimum width.
Schedule Dialog Error Handling (#5994
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When loading an existing schedule failed, the dialog opened as if nothing were scheduled, potentially allowing duplicate actions. The dialog now shows a warning toast and closes if the load fails.
Keyboard Shortcut Cleanup (#6004
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
useHotkeys now properly cleans up shortcuts when components unmount. Previously, unmounting while shortcuts were registered left them in the shared registry.
Fixed GraphQL Playground Tabs Shared Across Tenants (#5984
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The GraphQL playground’s saved tabs and query history were shared across all tenants because they were written to unprefixed local storage. Each tenant now gets its own isolated tabs and history. Data saved since version 6.5.0 may not appear after this fix, but data saved before 6.5.0 will show again.
Fixed Content Entry Views Failing to Load (#5979
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Opening CMS content entries, the compare revisions drawer, or file details in File Manager failed with “No registration found” errors. This was caused by singleton dependencies that expected per-view context. These views now work correctly.
Fixed Scheduler Dialog Not Showing Errors (#5982
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Failed schedule and cancel calls in the scheduler dialog reported success. They now show the error toast as expected.
Improved Breadcrumb Styling (#5985
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Clickable breadcrumb items now show a pointer cursor on hover. Text height is now consistent across all items, fixing descender clipping on labels like “Pages”.
Auto-Focus in Folder Dialogs (#5985
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The Create Folder and Edit Folder dialogs now auto-focus the title field, so you can start typing immediately.
Improved Dashboard Drop Target Visibility (#5956
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
While rearranging dashboard widgets, the drop target now matches the widget’s actual size and displays its name, making placement clearer.
Fixed Notifications Inbox Layout (#5978
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The notifications inbox now has proper header actions (Mark all as read, Reload), real tabs for Inbox and Archive, and an “Unread only” filter in the tab row.
Fixed Form Field Highlight Causing Layout Shift (#5978
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The “jump to field” highlight is now drawn with box shadows instead of padding. Previously, the padded highlight caused scroll areas to have extra scrollable space and the form to shift while the highlight was visible.
App-Wide Banners Above the Header (#5922
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A new banner system displays app-wide notifications above the Admin header. Banners come in four variants: info, success, warning, and error. The highest-severity banner is shown first; when severities match, the most recently shown banner takes priority.
import { useBanner } from "webiny/admin";
function MyComponent() {
const { showBanner, hideBanner } = useBanner();
const handleClick = () => {
showBanner({
id: "my-banner",
variant: "warning",
message: "Something needs attention",
action: {
label: "Fix it",
onClick: () => { /* ... */ }
},
dismissible: true
});
};
}For a banner whose lifetime is tied to a component, use the <Banner> component instead.
Permission Preview Returns to Starting Page (#5922
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When previewing permissions as a role or team, clicking “Exit preview” now returns you to the page where you started the preview, rather than reloading the current page.
Partial GraphQL Responses No Longer Throw (#5887
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The admin GraphQL client threw whenever a response had an errors array, discarding any data that was returned. GraphQL returns both on partial success—a failing non-nullable field nulls itself while the rest of data stays valid. The client now only throws when there’s no data at all.
Form Errors Stay in Sync After Rejected Saves (#5879
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Two bugs in the entry form’s error handling:
setErrors()didn’t clear the previous set, so old validation messages could persist after a successful save- A save that finished after the form was reset or replaced could write errors to the wrong form
Both are fixed. Errors are now cleared before applying a new set, and saves only update the form that initiated them.
Bug Reports Can Be Copied to Clipboard (#5880
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The bug report dialog (Cmd+Shift+B) now has a “Copy to clipboard” link. The copied report includes the description, environment details, and action timeline—useful for sharing via Slack or email instead of filing on GitHub. A “Copy bug report” command is also available in the command palette.
Folder Events Propagate via WebSocket (#5844
,#5852
,#5856
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Folder operations performed by the AI assistant now immediately update the admin UI without requiring a reload. This covers folder creation, access changes (grant/revoke), and deletion.
When the assistant creates, modifies, or deletes a folder, the server sends a notification to the user’s open browser tabs. The admin receives the event and updates its folder cache accordingly, including re-deriving inherited permissions for child folders when access changes.
Folder Deletion via AI Assistant (#5856
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The AI assistant can now delete folders. The approval prompt includes the folder’s title and indicates the action cannot be undone. Only empty folders (no subfolders or content) can be deleted.
Large Folder Permission Updates Complete Reliably (#5860
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Folder-level permission (FLP) updates on large folder trees now resume correctly after hitting a time limit. Previously, three bugs prevented continuation: the task returned “done” instead of “continue”, resumed runs always restarted from the top, and partially-processed branches were skipped entirely. Folders past the timeout point kept their old inherited permissions.
Scrollbar Improvements Across Dropdowns and Dialogs (#5824
,#5831
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Dropdown lists, popovers, and the command palette now use consistent scrollbar styling. Popovers scroll correctly with the mouse wheel inside dialogs, and dropdown lists stay open while dragging the scrollbar.
Form Validation Skipped for Empty Non-Required Fields (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Optional empty fields no longer trigger validation errors. Required fields retain their validation.
No Clear Action on Required Select Fields (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Required select fields no longer show a clear action, preventing users from accidentally clearing a mandatory value.
Folder Drop Confirmation (#5831
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Moving folders via drag and drop now prompts for confirmation before completing the move.
Redirect to Nearest Ancestor When Folder Deleted (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When the currently viewed folder is deleted, the UI now redirects to the nearest ancestor folder instead of showing an empty or broken state.
Customizable Dashboard Layout (#5804
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Users can now rearrange the admin dashboard to suit their workflow. Click “Customize” to enter edit mode, where widgets become draggable cards. You can change the number of columns (2, 3, or 4), remove widgets, and add new ones from a drawer that previews each widget. The layout is saved per user and remembered across sessions. While customizing, widget interactions are disabled to prevent accidental clicks during drag operations.
Preview Permissions as a Role or Team (#5763
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Administrators with full access can now see the Admin exactly as a specific role or team would. Open a role or team in Access Management, click “View as this role” (or team) in the form header, and the page reloads with that role’s permissions in effect. A banner above the breadcrumbs identifies the previewed role and provides an “Exit preview” button. While previewing, a control next to the tenant name lets you switch directly to another role or team.
This is not just a UI change—the API evaluates every request with the chosen role’s permissions. Lists shrink to show only what that role can see, and writes the role cannot make fail server-side. This answers questions like “why can this editor see that model?” by having the API respond as that editor would see it.
// The preview sends this header on every request
// x-webiny-assume-permissions: role:<id>
// or
// x-webiny-assume-permissions: team:<id>Only users with full access (* permissions) can preview as another role. The preview can only narrow permissions, never widen them.
Backspace Now Works in Textareas and Rich Text Fields (#5758
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The Backspace key was not working in textareas and rich text fields throughout the Admin, including the description field on the entry panel and Lexical fields in the entry form. The command palette’s global Backspace hotkey was intercepting the key press even when the palette was closed. This has been fixed—Backspace now only triggers palette behavior when the palette is open with a detail view showing, and it properly skips inputs, textareas, and contenteditable elements.
Fixed Feature Flag Resolution (#5695
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Feature flag resolution had several issues: a set of flags was enabled by default for anyone holding a license (rather than being properly gated), every unrecognized flag name resolved to enabled (including typos), and a project could not enable a flag it declared itself without a license. There are now only two kinds of flags: license-governed flags (where the license decides, and config can only disable) and project-owned flags (where the config decides, regardless of license).
Focus Lands on the Title Field When Creating a Page (#5644
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Opening the create page form no longer leaves the cursor nowhere. The title field is now focused automatically.
Teams, Roles and API Keys Accept a Null Description (#5641
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Creating or editing a team, role, or API key without a description and then saving the form again would fail silently — the API rejected the null value that came back from the initial save, and the admin app swallowed the error. Both issues are fixed: the API now accepts null descriptions consistently across all three entities, and save errors are surfaced in the UI.
File Manager "Re-Enrich With AI" Action (#5621
,#5622
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Images can now be re-enriched with AI from the file details drawer. The action streams the model’s output — description and tags — into the form fields as it arrives, and you choose whether to save the result. Previously AI enrichment only ran automatically on upload with no way to retry or preview.
The drawer layout was also reworked: the actions row now spans the full drawer width instead of being clipped inside the left panel.
AI Chat Mode in the Command Palette (#5589
)
Press Space on an empty command palette query, or Cmd+K a second time, to enter AI mode and ask questions about your project’s content in plain language. The assistant discovers your content models at runtime, queries entries based on your questions, and streams answers as the model produces them.⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
All queries run under your current identity and respect existing permissions — a user without CMS access will receive a permission error rather than data. Write operations (creating folders, granting access) require explicit approval before execution.
AI mode uses the provider configured in AI Power-Ups when installed. Without it, set WEBINY_API_AI_CHAT_MODEL in your environment variables to specify a model (defaults to anthropic/claude-sonnet-5).
Breadcrumb Navigation (#5496
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
A breadcrumb trail is now displayed in the admin header across all route-based pages. Breadcrumbs compose through the React Config API — mount <AdminConfig.Breadcrumb> components anywhere in your app, and the header renders them in mount order.
import { AdminConfig } from "webiny/admin";
// Static breadcrumbs (per route)
<AdminConfig.Breadcrumb name="dev-tools" label="Dev Tools" />
<AdminConfig.Breadcrumb name="graphql-playground" label="GraphQL Playground" />
// Dynamic breadcrumbs (e.g., folder paths)
{folderPath.map(folder => (
<AdminConfig.Breadcrumb
key={folder.id}
name={folder.id}
label={folder.title}
to={{ route: Routes.List, params: { folderId: folder.id } }}
/>
))}File Manager, Headless CMS, and Website Builder pages now display dynamic trails that reflect the current folder path or model name.
Workflow Editor Save Feedback (#5479
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Saving a workflow step now shows a “Workflow saved successfully” snackbar. Previously, the Save action gave no visual feedback.
Fixed WCP Project Query Missing Field (#5754
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The admin app’s WCP project query was requesting a websiteBuilder field that had been removed from the schema, causing the query to fail validation and preventing WCP project data from loading. The query has been updated to match the current schema.
File Manager
Scoped Uploads Now Tagged Correctly (#6031
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Files uploaded from a scoped File Manager are now tagged with that scope. Previously, uploads were saved with no tags, so they didn’t appear in the scoped view they were uploaded from.
File URL Generation No Longer Blocks Every Request (#5902
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
FileUrlGenerator.generateUrl() was synchronous, forcing schema composition to read File Manager settings from DynamoDB on every request. The method is now async and loads the URL prefix only when a file URL is actually resolved.
On a 1024 MB Lambda, warm request latency dropped from ~36ms to ~28ms at p50.
Fixed Image Crop Metadata Path (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Image crop data is now read from the correct metadata path. Previously, crop settings weren’t being applied due to a path mismatch.
Image Enrichment Failures Now Reported (#5828
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Failed image enrichment operations now display a warning toast with the error message. Previously, failures were logged server-side but the admin showed no indication that enrichment didn’t work—it looked identical to enrichment never running.
Private File Access Controls Gated Behind Feature Flag (#5831
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The access control UI in file details now only appears when the private files feature is enabled via the advancedAccessControlLayer.privateFiles feature flag.
Webiny SDK
Key-Value Store Collection Listing (#6023
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The key-value store now supports listing records by collection. A record joins a collection when you pass collection to set:
await kv.set(`aiChat:${ownerId}:${chatId}`, summary, {
collection: `aiChats:${ownerId}`
});
const page = await kv.list({
collection: `aiChats:${ownerId}`,
limit: 20,
cursor,
reverse: true
});Records without a collection are stored exactly as before and excluded from listings. Each collection is its own partition, so size is controlled by the caller.
OpenRouter AI Provider (#5954
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
OpenRouter is now available as an AI Powerups vendor. Configure it with the WEBINY_API_OPENROUTER_API_KEY environment variable. The provider includes a fallback list of 20 tool-capable models.
HTTP Response Streaming on Lambda and Self-Hosted (#5622
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Routes can now return an HttpStreamBody to deliver HTTP responses incrementally. On self-hosted Node the chunks arrive as the source produces them. On AWS the API uses a Lambda Function URL with response streaming, fronted by CloudFront.
import { HttpStreamBody } from "webiny/event-handler";
async function* generate() {
yield "data: first\n\n";
await delay(100);
yield "data: second\n\n";
}
return response.status(200).type("text/event-stream").send(new HttpStreamBody(generate()));Transports that cannot stream call collect() and return the whole body at once, so existing routes are unaffected.
CloudFront compression buffers chunks and defeats incremental delivery, so the /stream/* behavior disables it. The origin read timeout is raised to 60 seconds — it applies to the gap between packets, not the total stream duration.
Express-Style Response Builder for HTTP Routes (#5611
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
HTTP routes now receive a mutable response builder as a second argument, making it easier to set headers, cookies, and status codes:
async handle(request: IHttpRequest, response: IHttpResponseBuilder) {
return response
.status(201)
.cookie("sid", token, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 3600 })
.json({ id });
}Routes that return a plain IHttpResponse object continue to work unchanged. The new cookie() method is the only way to emit multiple Set-Cookie headers, which the old headers: Record<string, string> could not express.
HTTP Response Compression (#5612
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
HTTP responses are now compressed automatically when the client accepts it. The transport negotiates accept-encoding, preferring Brotli over gzip, and skips bodies under 1 KB or already-binary content. This restores the compression that was lost when we moved off Fastify and prevents large GraphQL responses from hitting the API Gateway size limit.
InjectableStringFormatterandSlugifyFeatures (#5549
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
New StringFormatter and Slugify features are now available in both @webiny/app-admin (frontend) and @webiny/api-core (backend), providing injectable, decoratable string formatting. This lets you customise slug generation across your project by decorating a single feature rather than hunting down individual usages.
import { Slugify } from "webiny/api-core";
const MySlugify = Slugify.createDecorator(() => {
return {
execute: value => {
return value.trim().toLowerCase().replace(/\s+/g, "_");
}
};
});
container.registerDecorator(MySlugify);A backend DateFormatter feature is also included for deterministic UTC date/time formatting.
Development Tools
Frontend Settings Shared Across CMS and Website Builder (#5941
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The preview domain and frontend starter kit configurations have moved from Website Builder into a new @webiny/frontend-settings package. CMS model previews now use a previewPath pattern resolved against this shared domain, replacing the older previewPrefix/previewSlug approach.
The Frontend Settings dialog is accessible from the Admin sidebar and requires the frontend-settings permission to modify settings.
Date Picker Shows Correct Day West of UTC (#5946
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Date-only values in the DatePicker now display as the stored calendar day regardless of the user’s timezone. Previously, users west of UTC would see the previous day.
Link Popover No Longer Clipped in Object Fields (#5946
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The lexical editor’s link popover now repositions correctly when the rich text field is inside an object field, preventing the popover from being clipped.
Scheduler
Access Now Follows App Permissions (#5907
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Scheduler access was governed by a scheduler.action permission that the admin couldn’t grant. Users with CMS or Website Builder roles got NotAuthorizedError when trying to schedule actions.
Access now follows the permissions of the app that owns the scheduled action. A user with cms.contentEntry access can schedule, list, and cancel CMS actions; a user with Website Builder page-publish permissions can do the same for WB actions.
Audit Logs
Listing Audit Logs Now Requires Permission (#5886
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
listAuditLogs returned every audit log to any signed-in identity. It now requires full audit-log access (* or al.*), matching the rule getAuditLog uses.
Merging No Longer Wipes Tags (#5877
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When audit logs merged repeated updates within the newEntryDelay window, the merge reset the original log’s tags to an empty array. The merge now only updates message and content, preserving tags.
WebSockets
Undelivered Messages Are Now Logged (#5870
)
⏳ REVIEW-PENDING
@Pavel910: confirm this entry, then delete this line.
When a WebSocket message reached no connection (for example, if the user closed all tabs), the send silently succeeded. It now logs a warning with the identity and action, making delivery failures visible in logs.
Page Builder
AI Page Translation Uses Correct Source Language (#5851
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Page translation now reads the language from the original source page rather than the translated copy. Previously, the prompt would say “translate from de to de” because the copy already had the target language set.
AI Translation Handles Fenced JSON Responses (#5851
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
When an AI model wraps its translation response in a ```json fence or adds explanatory text, the page translator now correctly extracts and applies the JSON. Previously, these responses caused a parse failure and left pages silently untranslated.
AI
Google Added as AI Provider (#5850
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Google Gemini models are now available as an AI provider alongside OpenAI and Anthropic. Configure it in AI Power-Ups → Connections using your Google API key, or set the WEBINY_API_GOOGLE_API_KEY environment variable.
AI Model List Loaded From WCP (#5863
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The available AI models are now fetched from WCP’s /ai/models endpoint instead of relying solely on hardcoded lists. The catalog is cached for one hour per process. If WCP is unreachable, the SDK factory’s built-in list is used as a fallback.
Model entries now include deprecated and endOfLife dates where available. Requesting a model that isn’t in the registry is now rejected with “Model … is not available” instead of being passed directly to the SDK.
AI Entry Wizard Gated Behind License (#5824
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The AI entry generation wizard only appears when the aiPowerups.cms.entryGeneration feature flag is enabled.
AI Powerups
Admin Assistant Is Now a Configurable Capability (#5725
,#5730
,#5733
,#5735
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
The Admin Assistant (the AI chat in the command palette) is now managed through the AI Powerups settings like all other AI capabilities. You can configure which model it uses, pin it to a specific connection, and append custom instructions to its prompt—all from Settings → AI Power-Ups → Capabilities.
The assistant is now properly gated by the aiPowerups.adminAssistant license flag. Previously, it was available in all projects regardless of licensing. Projects without the appropriate license will no longer see the AI commands in the command palette.
The assistant no longer falls back to environment variables or hardcoded models. If no model is configured for the required role, the assistant will explain what setting needs to be configured rather than failing silently.
Per-Capability Enable/Disable Controls (#5750
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Each AI capability can now be individually enabled or disabled. When a license grants a capability, it is enabled by default. The toggle in AI Powerups settings lets you turn off capabilities you don’t want to use. A disabled capability won’t run—both the UI controls and the API mutations are blocked—but its configuration is preserved for when you re-enable it.
License Now Governs All AI Features (#5728
,#5732
,#5745
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
Several AI capabilities were checking only project configuration, not the WCP license. A project could enable capabilities it hadn’t licensed. All AI Powerups features now properly check both the license and project configuration:
- Entry generation, comparison, and translation
- Page generation and translation
- Lexical generation
- Image enrichment
- Remote components (moved under
aiPowerups)
The AI Powerups extension now gates itself at runtime rather than deploy time, so license changes take effect immediately without redeploying.
AI Power-Ups
Per-Capability AI Model Resolution (#5691
)
⏳ REVIEW-PENDING
@adrians5j: confirm this entry, then delete this line.
AI features previously used whatever model happened to be first in the providers list. This has been replaced with a three-layer configuration:
- Connections — credentials for a vendor, carrying no model. Using two models from the same vendor no longer requires duplicating the API key.
- Model roles —
fast,standard,vision. Named slots you fill once in settings. - Capabilities — one per AI feature, allowing you to move a feature to a different role, pin an exact connection and model, or append instructions to its prompt.
Existing projects keep working without changes — standard is seeded from your existing provider configuration.