For the full list of changes, check out the Webiny 6.6.0external link release on GitHub.

Development
anchor

Standalone Hosting: Run Webiny Without AWS (#5454external link)
anchor

{/ 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 standalone

Standalone 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.tsx with <Infra.Sqlite> or <Infra.Postgres>, and the build leaves out the driver you don’t use.
  • One command for local development. yarn dev starts the API and Admin and serves both on one URL. The port comes from the PORT environment variable, or the first free port from 3001.
  • Deployable builds. webiny build produces a self-contained build/ folder with the server entry point, worker files and a pruned node_modules, ready to copy to any server. Example GitHub Actions workflows, a Dockerfile and an nginx config are in docs/gh-actions-workflows/standaloneexternal link.
  • 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 with yarn webiny reset-password <email>.
  • Licensing without the CLI. A deployed server reads the license from the WEBINY_PROJECT_ID and WEBINY_PROJECT_API_KEY environment variables.

New projects run without a .env file and ship a .env.example that lists the variables you can override.

Related PRs: #5453external link, #5510external link, #5511external link, #5516external link, #5527external link, #5500external link, #5697external link, #5635external link, #5715external link, #5713external link, #5717external link, #5729external link, #5718external link, #5664external link, #5408external link, #5414external link, #5915external link, #5963external link, #6022external link, #5525external link, #5547external link, #5541external link, #5825external link, #5687external link, #5926external link, #5988external link, #5968external link, #5398external link.

TypeScript 7 Compatibility (#5380external link)
anchor

{/ 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 (#5559external link)
anchor

{/ 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 (#5519external link)
anchor

{/ 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 (#5410external link)
anchor

{/ 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 (#5364external link)
anchor

{/ 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 (#6005external link)
anchor

⏳ 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 (#6002external link)
anchor

⏳ 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 (#5830external link)
anchor

⏳ 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 (#5848external link)
anchor

⏳ 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 (#5848external link)
anchor

⏳ 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 (#5765external link,#5773external link,#5779external link,#5781external link,#5790external link,#5811external link)
anchor

⏳ 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 (#5781external link,#5786external link)
anchor

⏳ 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 (#5775external link)
anchor

⏳ 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 (#5810external link)
anchor

⏳ 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 (#5736external link,#5746external link)
anchor

⏳ 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 (#5752external link,#5755external link)
anchor

⏳ 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 --help

CLI Tracing (#5741external link)
anchor

⏳ REVIEW-PENDING @adrians5j: confirm this entry, then delete this line.

A new --trace flag shows where CLI time is spent:

yarn webiny <command> --trace

The report shows nested phases with durations and percentages, helping identify bottlenecks in project configuration or extension validation.

Lazy Route Matching Reduces Cold Start Cost (#5668external link)
anchor

⏳ 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 (#5591external link)
anchor

⏳ 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 (#5539external link)
anchor

⏳ 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 (#5570external link,#5569external link,#5562external link)
anchor

⏳ 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 (#5457external link)
anchor

⏳ 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 (#5771external link)
anchor

⏳ 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 (#5799external link)
anchor

⏳ 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 (#5722external link)
anchor

⏳ 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 (#5472external link)
anchor

⏳ 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 (#5532external link,#5537external link)
anchor

⏳ 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 (#5684external link,#5692external link,#5699external link,#5706external link,#5709external link,#5710external link,#5711external link)
anchor

⏳ 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:

  • TaskDefinition carries only metadata (id, title, maxIterations, etc.) and has no dependencies
  • TaskHandler contains run() 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 (#5673external link)
anchor

⏳ 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 (#5706external link)
anchor

⏳ 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 (#5483external link,#5484external link,#5486external link,#5492external link,#5493external link,#5495external link)
anchor

⏳ 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
anchor

Modernised Storage Operations Architecture (#5490external link)
anchor

{/ 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 (#5487external link,#5450external link,#5431external link)
anchor

{/ 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 (#5473external link)
anchor

{/ 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 (#5473external link)
anchor

{/ 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 (#5413external link)
anchor

{/ 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 (#5529external link)
anchor

{/ 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 (#5402external link)
anchor

{/ 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 values JSONB 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 (#5812external link)
anchor

⏳ 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 (#6033external link)
anchor

⏳ 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 (#6019external link)
anchor

⏳ 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 (#6008external link)
anchor

⏳ 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 (#6015external link)
anchor

⏳ 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 (#5982external link)
anchor

⏳ 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 (#5982external link)
anchor

⏳ 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 (#5982external link)
anchor

⏳ 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 (#5955external link)
anchor

⏳ 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 (#5937external link)
anchor

⏳ 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 (#5937external link)
anchor

⏳ 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 (#5932external link)
anchor

⏳ 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 (#5954external link)
anchor

⏳ 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 (#5947external link)
anchor

⏳ 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 (#5954external link)
anchor

⏳ 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 (#5946external link)
anchor

⏳ 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 (#5914external link,#5912external link)
anchor

⏳ 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 (#5888external link)
anchor

⏳ 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 (#5909external link)
anchor

⏳ 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 (#5913external link)
anchor

⏳ 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 null flags

Fixed$.Rule Targets Inside List Items (#5865external link)
anchor

⏳ 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 (#5865external link)
anchor

⏳ 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 (#5865external link)
anchor

⏳ 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 (#5865external link)
anchor

⏳ 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 (#5854external link)
anchor

⏳ 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 (#5854external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5807external link)
anchor

⏳ 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 (#5809external link)
anchor

⏳ 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 (#5719external link)
anchor

⏳ 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 (#5762external link)
anchor

⏳ 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 (#5700external link)
anchor

⏳ 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 (#5657external link)
anchor

⏳ 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 (#5632external link,#5633external link,#5634external link,#5636external link,#5638external link,#5639external link,#5645external link,#5650external link,#5651external link,#5654external link)
anchor

⏳ 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 (#5620external link)
anchor

⏳ 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 (#5479external link)
anchor

⏳ 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 (#6009external link,#6003external link)
anchor

⏳ 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 (#6009external link)
anchor

⏳ 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 (#6003external link)
anchor

⏳ 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 (#5940external link,#5951external link,#5962external link,#5965external link)
anchor

⏳ 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
anchor

Replaced VulnerabledecompressLibrary (#5521external link)
anchor

{/ 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 (#5475external link)
anchor

{/ 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 (#5370external link)
anchor

{/ 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 (#5889external link)
anchor

⏳ 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 (#5869external link)
anchor

⏳ 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 (#5866external link)
anchor

⏳ 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 (#6002external link)
anchor

⏳ 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 (#6002external link)
anchor

⏳ 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 (#5964external link)
anchor

⏳ 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 (#5983external link)
anchor

⏳ 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 (#5976external link)
anchor

⏳ 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 (#5916external link,#5924external link)
anchor

⏳ 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 (#5934external link)
anchor

⏳ 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 (#5933external link)
anchor

⏳ 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 (#5950external link)
anchor

⏳ 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 (#5899external link,#5900external link)
anchor

⏳ 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 (#5846external link)
anchor

⏳ 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 (#5828external link)
anchor

⏳ 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 (#5802external link,#5808external link,#5822external link)
anchor

⏳ 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 (#5737external link)
anchor

⏳ 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 (#5694external link)
anchor

⏳ 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 (#5685external link)
anchor

⏳ 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 (#5646external link)
anchor

⏳ 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 (#5637external link)
anchor

⏳ 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 (#5504external link)
anchor

⏳ 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 (#5523external link)
anchor

⏳ 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(#5456external link)
anchor

⏳ 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(#5466external link)
anchor

⏳ 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 (#5465external link)
anchor

⏳ 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
(#5981external link,#5980external link)
anchor

⏳ 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 (#5980external link)
anchor

⏳ 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 (#5969external link)
anchor

⏳ 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
anchor

Feature Flags Replace WCP as Primary Feature Availability System (#5559external link)
anchor

{/ 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:

  1. No license → feature disabled
  2. License blocks the flag → feature disabled (config ignored)
  3. License allows + config explicitly false → feature disabled
  4. License allows + config unset → feature enabled (license is authority)
  5. 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
anchor

Tags, DateTime and RadioGroup Inputs Now Work in the Component Editor (#5891external link)
anchor

⏳ 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 (#5892external link)
anchor

⏳ 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 (#5890external link)
anchor

⏳ 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 (#5872external link)
anchor

⏳ 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 (#5871external link)
anchor

⏳ 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 (#5873external link)
anchor

⏳ 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 (#6032external link)
anchor

⏳ 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 (#6004external link)
anchor

⏳ 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 (#6004external link)
anchor

⏳ 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 (#6004external link)
anchor

⏳ 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 (#6002external link)
anchor

⏳ 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 (#5943external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5805external link)
anchor

⏳ 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 (#5671external link)
anchor

⏳ 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 (#5479external link)
anchor

⏳ 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 (#6009external link)
anchor

⏳ 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 (#6009external link)
anchor

⏳ 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
anchor

AI Power-Ups Settings Can Be Saved After Model Retirement (#5867external link)
anchor

⏳ 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 (#5868external link)
anchor

⏳ 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 (#5993external link)
anchor

⏳ 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 (#5994external link)
anchor

⏳ 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 (#6004external link)
anchor

⏳ 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 (#5984external link)
anchor

⏳ 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 (#5979external link)
anchor

⏳ 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 (#5982external link)
anchor

⏳ 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 (#5985external link)
anchor

⏳ 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 (#5985external link)
anchor

⏳ 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 (#5956external link)
anchor

⏳ 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 (#5978external link)
anchor

⏳ 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 (#5978external link)
anchor

⏳ 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 (#5922external link)
anchor

⏳ 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 (#5922external link)
anchor

⏳ 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 (#5887external link)
anchor

⏳ 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 (#5879external link)
anchor

⏳ 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 (#5880external link)
anchor

⏳ 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 (#5844external link,#5852external link,#5856external link)
anchor

⏳ 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 (#5856external link)
anchor

⏳ 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 (#5860external link)
anchor

⏳ 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 (#5824external link,#5831external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5831external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5804external link)
anchor

⏳ 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 (#5763external link)
anchor

⏳ 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 (#5758external link)
anchor

⏳ 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 (#5695external link)
anchor

⏳ 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 (#5644external link)
anchor

⏳ 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 (#5641external link)
anchor

⏳ 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 (#5621external link,#5622external link)
anchor

⏳ 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 (#5589external link)
anchor

⏳ REVIEW-PENDING @adrians5j: confirm this entry, then delete this line.

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.

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 (#5496external link)
anchor

⏳ 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 (#5479external link)
anchor

⏳ 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 (#5754external link)
anchor

⏳ 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
anchor

Scoped Uploads Now Tagged Correctly (#6031external link)
anchor

⏳ 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 (#5902external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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 (#5828external link)
anchor

⏳ 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 (#5831external link)
anchor

⏳ 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
anchor

Key-Value Store Collection Listing (#6023external link)
anchor

⏳ 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 (#5954external link)
anchor

⏳ 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 (#5622external link)
anchor

⏳ 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 (#5611external link)
anchor

⏳ 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 (#5612external link)
anchor

⏳ 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 (#5549external link)
anchor

⏳ 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
anchor

Frontend Settings Shared Across CMS and Website Builder (#5941external link)
anchor

⏳ 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 (#5946external link)
anchor

⏳ 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 (#5946external link)
anchor

⏳ 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
anchor

Access Now Follows App Permissions (#5907external link)
anchor

⏳ 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
anchor

Listing Audit Logs Now Requires Permission (#5886external link)
anchor

⏳ 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 (#5877external link)
anchor

⏳ 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
anchor

Undelivered Messages Are Now Logged (#5870external link)
anchor

⏳ 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
anchor

AI Page Translation Uses Correct Source Language (#5851external link)
anchor

⏳ 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 (#5851external link)
anchor

⏳ 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
anchor

Google Added as AI Provider (#5850external link)
anchor

⏳ 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 (#5863external link)
anchor

⏳ 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 (#5824external link)
anchor

⏳ 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
anchor

Admin Assistant Is Now a Configurable Capability (#5725external link,#5730external link,#5733external link,#5735external link)
anchor

⏳ 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 (#5750external link)
anchor

⏳ 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 (#5728external link,#5732external link,#5745external link)
anchor

⏳ 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
anchor

Per-Capability AI Model Resolution (#5691external link)
anchor

⏳ 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.