This release adds selective system restores, scheduled volume backups, Convert to Compose, direct image patching, Apple push notifications, and ML-DSA-87 signing for authentication and edge mTLS.
It also improves upgrade reliability, image update discovery, project logs, Swarm access, backup downloads, and UI performance.
Backups and recovery
Add selective system restores and harden recovery β 874134cfedc2e8ae44e6f0cd7e957e87bc760988 (#3708) (@neurekadev)
Preserve stderr streams and Docker timestamps in project logs β cac8a9090baea3b44aa2868d195cd21c3dcf62f0 (#3770) (@kmendell)
Allow the Viewer role to browse Swarm resources β 3f205dea94fa6d40189cf80eec665e39c5131e60 (#3779) (@kmendell)
Trigger agent self-upgrades asynchronously and pass the managerβs resolved target version β d857910d9b08f96e7739c679415b18fd192a01b4 (#3786) (@kmendell)
Serialize explicit empty values in partial-update DTOs with omitzero β 24592561d9154da35d7fecd380e12c50e3c5783a (@kmendell)
Authentication and notifications
Add native Apple push notifications for the iOS app β 4b1abefec6b9b93ea331e1259e061c6862025a11 (#3783) (@kmendell)
Sign and verify sessions, OIDC, passkeys, and edge mTLS with ML-DSA-87 β 2993fd316d41fafc110476370870a49b9202969c (#3785) (@kmendell)
Accept display names in email notification From addresses β 034e7e7efd4e756f0c3145099f24f2afe0bc7596 (#3776) (@ohOgil)
User interface
Improve table-scrolling performance across all views β 1243d8e0bafdc110b8443ef710d999e5104ce632 (@kmendell)
Keep dialog widths within the content area β 5e7acb61d3bb6ef4bc60a80266c424f1d40d02c2 (@kmendell)
Move frontend files into a more maintainable structure β 938882a174322a1bbc6fe50fe926a4c61820797b (@kmendell)
Dependencies
Bump github.com/aquasecurity/trivy from 0.69.3 to 0.72.0 in /backend β 29784fead298d740fb07db2754d53ff55e3bb9c4 (#3748) (@dependabot[bot])
Bump github.com/sirupsen/logrus from 1.10.0 to 1.10.1 in /backend β be4220fa2cc44c348177de5c39354b716a517413 (#3753) (@dependabot[bot])
Bump github.com/quay/claircore from 1.5.52 to 1.5.53 in /backend β 611b5d7ff298ccd51b0675874354282aa117356c (#3747) (@dependabot[bot])
Bump github.com/samber/hot from 0.13.0 to 0.13.1 in /backend β cecdb777ec0f3487ab442f2bd1a45dc1120f0564 (#3754) (@dependabot[bot])
Bump charm.land/bubbles/v2 from 2.2.0 to 2.2.1 in /cli β b631dd67c34ef642c3bb177ad3d9df09c0974b0d (#3752) (@dependabot[bot])
Bump @tanstack/svelte-query from 6.1.39 to 6.1.43 β 55762896904d9453f2c2cbeb26645b6e0f6818a2 (#3761) (@dependabot[bot])
Bump github.com/google/go-containerregistry from 0.21.9 to 0.22.0 in /backend β 3c0aac7c557ace8a15ffbd60dd6dc4448ec43a93 (#3755) (@dependabot[bot])
Bump marked from 18.0.10 to 18.0.11 β 201a3ff183a0f07e342398d0b1b12ca3847777a5 (#3759) (@dependabot[bot])
Refactoring
Use generics to eliminate redundant logic β 671ebef57234c40acba287925c5ee6ac9efdd399 (#3683) (@kmendell)
Migrate JWT and JWKS handling to jwx v4 β 45b063a074f521f45591f58c7b1d89b4395dc267 (#3790) (@kmendell)
After upgrade, you need to run php bin/console doctrine:migrations:migrate (or equivalent) as webserver user after upgrade.. If you are running a docker container, use sudo docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate, or sudo -E inside the docker container, to ensure that the migrations are applied to the correct database.
Note
If you are using Part-DB it would be helpful if you fill out this short survey on your usage of Part-DB (Google Forms): https://forms.gle/Q15twx3YYq3qCNfe8
Part-DB 2.16.0
New Features
Add a component image generator for resistors, capacitors and inductors @Sebbeben in #1435
Improved KiCAD API which should massively increase load speeds in KiCAD (after PR #1489)
Added MCP tools to get attachment contents
Added MCP tools to create, edit and delete parts, storage locations, categories, footprints, manufacturers and suppliers
Log the access_method in change logs, to see whether the change was done via WebUI, REST API or MCP
Log an unique request ID with change logs, so that all changes done in a single request can be easily grouped together
Show max_input_vars and sqlite enforce fk status in server info page
Allow to create a new lot at new location via lot move dialog @calebwest-SS in #1500
Allow to edit part BOM entries from BOM table (PR #1488)
Added "performance mode" for projects. When an project has more than 100 entries, the BOM cannot be edited via the project admin page anymore to avoid issues with too large forms.
Calendar / Auth: Pin the resolved IP address at socket-connect time when fetching caller-supplied URLs (iCalendar subscriptions, JMAP login and TOTP token-exchange servers). The public-host check used to run before fetch() opened its socket, so an attacker who controlled DNS for a hostname could rebind it to loopback, RFC-1918 or cloud-metadata addresses between the check and the connect and read up to 10 MB of the internal response through the unauthenticated /api/fetch-ical endpoint. Redirect targets are now validated the same way (GHSA-24w9-8r42-8jwm, thanks @Tike00)
Features
Push: Re-sync existing push registrations in the background on app start, so registrations created before the delivery filter existed β or whose Junk mailbox id went stale β get repaired without re-enabling notifications
Fixes
Push: Stop sending notifications for spam β the push subscription now carries a JMAP emailPush delivery filter that excludes $junk and the Junk mailbox (needs a server advertising the emailPush capability, e.g. Stalwart β₯ 0.16.16; older servers keep the previous behaviour)
Navigation: Forward every request header through the proxy β Next 16.3's RSC header check rejected the stripped router headers and sent navigations into a 307 redirect loop (#919)
Calendar: Stop emitting RSCALE=GREGORIAN;SKIP=OMIT on plain Gregorian recurrence rules β DAVx5 rejected them as invalid and Android sync broke (#805, thanks @hildebrandttk)
A complete revamped Media Library UI is available behind a feature flag. Set future.betaMediaLibrary: true in config/features and restart your app; it replaces the legacy Media Library when enabled (disabled by default). More info in docs and the Notion Page
Feedback while it's behind the flag is very welcome. Enjoy!
π₯ Bug fix
make drag and drop more fluently in configuation view fix#23161 (#26320, #23161)
admin: out of sort memory when listing audit logs on mysql (#27410)
admin: send credentials on fetch client requests (#27413)
admin: keep api token permissions on localized content types at boot (#27420)
admin: honour redirectTo when the auth page redirects an authenticated user (#27213)
admin: slow startup with many roles due to redundant permission β¦ (#27438)
content-manager: draft status filter with i18n sibling locale published (#26835)
content-manager: reject MCP relation writes combining set with connect or disconnect (#27423)
content-manager: out of sort memory when listing history versions on mysql (#27394)
core: Access token rotation fails with asymmetric JWT algorithms (#27201)
core: serialize JSON columns before INSERT in discard-drafts migration (#25927)
core/strapi: local plugins duplicate the admin module graph and exhaust build memory (#27311)
database: relation reorder saves the wrong position (#27444)
i18n: correct broken placeholders in pt-BR translations (#27257, #27383)
permissions: surface clear error for unsupported RBAC condition operators (#27355)
plugins: admin build fails to resolve @strapi/admin under isolated node_modules (#27337)
upload: translate server error codes in the new media library (#27345)
upload: sizeLimit is not enforced when replacing a file (#27414)
upload: move replace media to the drawer footer, add tooltips (#27425)
upload: list queued files in the upload progress dialog (#27416)
upload: merge a second drop into the running upload batch (#27415)
βοΈ Chore
replace lodash forEach with native Object.entries/values (#27409)
graphql: warn about unbounded operation limits (#27390)
upload: deny svg in generated project defaults (#27360)
β οΈ Changes to be aware of
New projects block SVG uploads by default
Apps created with create-strapi-app now reject SVG files in the Media Library by default, because SVG can include active browser content. Existing projects are unchanged; if you need SVG in a new project, allow image/svg+xml in the generated upload security config.
(#27360)
Mail: Search suggestions with recent searches and contact autocomplete (#845)
Mail: Render plain-text emails in the app font by default, with a monospace option (#830)
Mail: Pull-to-refresh indicator while dragging the list down (#826)
Mail: Redesigned unread favicon badge β a compact keyline badge
Mobile: Swipe message rows left or right for quick actions β archive, delete, toggle read, toggle star, or spam, configurable per direction, RTL-aware
Pro: Reworked split-screen shell with per-pane tab strips, drag & drop between panes, and pane-scoped overlays
Pro: Folder tabs via drag & drop
Pro: The address bar follows the focused tab, and deep links are delivered live to already-mounted surfaces
Composer: Real byte progress for attachment uploads, stock and plugin-offloaded; cancel now aborts the transfer itself
Calendar: Moving an event's start moves the end with it, keeping the event's length
Contacts: Trusted Senders address book enabled by default on contacts-capable accounts
Settings: Custom time zone setting that overrides browser detection (#755)
Login: Server dropdown on the OAuth-only login screen (#799)
Push: New-mail notifications grouped per account with a "+N more messages" line instead of one notification per message
Push: Per-device revoke for push subscriptions (#841)
Admin: Configurable Stalwart admin access to the dashboard (#870)
Admin: Push relay picked from an admin-defined list instead of a free URL field
Branding: OpenGraph/Twitter link previews with a generated card image
Plugins: onBeforeComposeOpenToReply and sibling hooks let a plugin edit an email before it populates the composer for reply or forward
Plugins: getPublicKeyFromWKD
Plugins: Privileged plugins can fetch a byte range of a blob
Plugins: progressFileId on api.http.post so an offloaded upload reports byte progress to the composer chip
Plugins: isActive on AccountResponse
Plugins: Label settings and label reordering exposed to extensions
Plugins: JMAP keyword helpers and gateway keywords exposed to extensions
Plugins: Mailbox refresh hook
Dev: AddressBook/set in the dev mock JMAP server
Changes
Plugins: The PRF getOrCreate flow is split into separate get and create steps for better authenticator compatibility (#851)
Dependencies: Next 16.3.3, pdfjs-dist 6.2.108, DOMPurify 3.4.14 (npm audit)
Fixes
Send: Route scheduled sends to the account that owns the submission β mail scheduled from a shared address can now be listed, cancelled, and rescheduled instead of going out silently (#874)
Send: Split recipient lists whose angle brackets never close without dropping recipients
Send: generateMessageId crashed on insecure origins (crypto.randomUUID undefined), failing the send after the draft save
Composer: Keep attachments when re-opening a draft, also in the Pro draft tab, and destroy old draft versions only after a successful create or send (#849)
Composer: Keep the signature in saved drafts and embed it into re-opened drafts (#848)
Composer: Double-click unlocks the embedded signature for editing
Composer: Keep already written text when applying a template (#540)
Composer: Preselect the shared folder's identity for new messages
Composer: Namespace all accounts consistently in the Pro composer identity list
Composer: Opening a mailto: link runs the unsaved-draft dialog instead of replacing the draft outright
Composer: Keep the fresh-compose tab title clear of the selected email subject
Composer: Clear the viewer when sending destroys the displayed draft
Reply: Honour an external Reply-To even on a self-sent message
Mail: Flip $junk/$notjunk keywords on spam and not-spam (#850)
Mail: Remove keywords with null rather than false in Email/set, per RFC 8620
Mail: Escape the JSON Pointer in keyword patches so nested tags like work/clients patch the right keyword
Mail: Route keyword writes β tags, pins, flags β to the selected shared account so they persist
Mail: Route shared-folder management to the owner account, scoped to one server
Mail: Open the right conversations in a shared mailbox (#814)
Mail: Route multi-account email lookups and invitation parsing by source account (#847), and parse invitations in directly viewed shared folders against the folder owner (#867)
Mail: Folders containing a system folder name no longer disappear from the sidebar (#771)
Mail: Folder drag & drop can move folders into other parents (#855)
Mail: Keep the folder tree when a refresh burst hits maxConcurrentRequests (#780)
Mail: Stop All-Mail and cross-account views emptying on delete, star, or mark-read (#791)
Mail: Keep just-read or unstarred mail in the open Unread/Starred view
Mail: Search folder filter defaults to all folders and persists (#788)
Mail: Fixed-width read/unread toolbar button so buttons don't jump when a message opens (#864)
Mail: Transparent hover-action background on tagged rows
Mail: Enforce the external media preference on plugin-rendered bodies (#797)
Mail: Apply the data: URI allowlist to media tags and srcset candidates too
Mail: Make label reordering atomic
Mail: Pass PDF bytes to pdf.js instead of fetching the blob: URL that CSP connect-src blocks (#871)
Mail: Include email templates in cross-device settings sync (#825)
Mail: Toast store crashed on insecure origins, breaking every post-action acknowledgement
Mobile: Reach the tag and move submenus in the more-actions menu (#779)
Mobile: iOS Safari no longer zooms the viewport on every input focus (#838)
Calendar: Click and double-click create events at the clicked slot instead of near the current time
Calendar: Save and Cancel are available when an event is created, and the toolbar no longer overflows in edit mode
Calendar: Edit a single recurring occurrence via a one-shot override patch
Calendar: Hide tasks-only calendars from the event calendar
Calendar: Exclude subscription and read-only calendars from event creation (#762)
Calendar: Rights-first event editability, including alias organizers
Calendar: Pin supported-calendar-component-set on created calendars (#760)
Calendar: Gate first-touch calendar and contacts requests to stop duplicate default calendars (#907)
Calendar/Contacts: Namespace all accounts consistently on switch, so multi-account address-book aggregation and calendar selection survive an account switch
Contacts: Import vCard dates as RFC 9553 PartialDate and map common X- extensions (#224)
Files: Decode percent-encoded FileNode names from WebDAV-created nodes (#869)
Files: Reset the account-scoped Files drive on every account switch
Accounts: Refresh the account display name from the Stalwart principal on login, restore, and switch (#900)
Auth: Reuse the cached access token on session restore (#552)
Auth: Refresh TOTP-minted tokens with the default client id when no OAuth client is configured (#873)
Auth: Store the session cookie for relative JMAP server URLs
Security: Close IPv6 transition-address and redirect bypasses in the endpoint guard
Security: Add embedded custom app origins to CSP frame-src (#787)
Security: Per-account isolation for encryption at rest
JMAP: Cap live SSE streams per tab and keep exactly one stream per client, so many logins can't starve JMAP requests (#702)
JMAP: Check the specific capability a request declares (principals:owner), not a broader one
JMAP: Resolve relative session URLs without corrupting URI templates
Settings: Merge per-account maps on server load, fixing the compose identity switch
Settings: Leaving the Pro interface returns to the surface in use and keeps the settings scroll position
UI: Position portalled popovers before first paint to stop the layout flash on open
Push: Recreate the push subscription on re-register (#841)
i18n: Key parity across all 24 locales, Catalan and Mongolian registered in the client provider, and scoped translation hooks instead of relative namespace paths
Docs: Lengthen the example SESSION_SECRET so it meets the minimum length
Added countFilterListeners, countActionListeners, and countInitListeners methods to the emitter, exposing the number of registered handlers for each event (#28117 by @ComfortablyCoding)
π Bug Fixes & Optimizations
@directus/app
Fixed MCP OAuth clients settings pages concatenating breadcrumbs into the page title (#28115 by @MHJahanbakhsh)
@directus/api
Fixed the WebSocket heartbeat leaking a websocket.message listener on each ping when a client failed to respond in time (#28117 by @ComfortablyCoding)
Stripped project_id when pulling settings, so a sync no longer copies one instance's identity onto another (#28132 by @lazerg)
@directus/sdk
Fixed unsubscribe() not removing subscriptions, causing them to persist across reconnects and accumulate for the lifetime of the client (#28117 by @ComfortablyCoding)
@directus/system-data
Removed user_created and date_created for update from recommended permissions for directus_shares (#28145 by @br41nslug)
This release adds automated S3 backups, standalone container editing, batched container-update notifications, and GitOps redeployment for stopped projects.
It also expands the CLI with commands for vulnerabilities, activities, and webhooks while improving project handling, OIDC support, and API behavior.
Add the ability to edit standalone containers β 24894fc7310b747e95d2b5d59e0a5100bb8bf12f (#3646) (@kmendell)
Add renaming for unused volumes β 1e413ada2f2413fa2a7c97798288b73ddb9d6b6c (#3704) (@neurekadev)
Pull and redeploy images after GitOps sync for stopped projects β f17e84412ae41dac1945f5b6896bafce8c244bb9 (#3698) (@ohOgil)
Add CLI commands for the latest server features and adopt hyphen-free command naming β d84511b8d67bef5fe3117832c9173ecc987e38da (@kmendell)
Add CLI commands for vulnerabilities, activities, and webhooks with end-to-end coverage β f4f9df0e8f1373a9e7fcba145383fcda8b4b3fc2 (@kmendell)
Fixes
Ensure stable ordering for page walks without an explicit sort β bf783a828ef816acf789851dffb2b8b8ed249450 (#3648) (@kmendell)
Percent-decode API path parameters before use β c469305cdacf49b80f7f5639f00eef597c1ca102 (#3682) (@kmendell)
Show Git-synced project files as read-only instead of hiding them or crashing β da21e2694754434d9b6b936834aed44173378ef1 (#3690) (@kmendell)
Send the build directive for projects from the backend β 53017c67cf91656965d667bf23e80dc0b46bd482 (#3691) (@kmendell)
Allow assigning roles to OIDC users and handle username collisions during OIDC login β c38c2580fb14f8a8f15f74ef9203bfdb9896c466 (#3692) (@kmendell)
Make the update-all dialog scroll correctly with large fleets β b7a619b2c7f8f08f05cc78f3db51ac6aa63e9ef4 (@kmendell)
Validate cgroup-derived container IDs during self-detection with network_mode: service β c24013107eff0adba0813b66b50350a03a487895 (#3710) (@kmendell)
Handle updates to discovered Compose projects β 275aface140f0d41e67adef402859f8a2a6ba207 (#3711) (@kmendell)
Refactoring
Upgrade to Go 1.27.0 β b22edb6909c5497f3e72e27d4570551c7fb2fe91 (#3680) (@kmendell)
Use native Temporal for time and date parsing β 60c2dee13cd9405175b6e0a5d65053724bb005cd (#3714) (@kmendell)
Use AI generation for GitHub release notes β 2240e8f0c7a49331f3ba7e385d7b793b844fbcaa (#3739) (@kmendell)
Dependency updates
Bump @sveltejs/kit from 3.0.0-next.21 to 3.0.0-next.23, then to 3.0.0-next.25 β cd8c48b36c926a5342a5b83f373269e4ec4093a1 (#3672), 70475a2cf7ca52f2d017422551ce645e4507aaa4 (#3727) (@dependabot[bot])
Bump svelte from 5.56.8 to 5.56.9, then to 5.56.10 β d4d83941e2685a2273a6437670d17b71816d5620 (#3666), 1478dd7df710c42161b16f7cb07be79193e7570b (#3724) (@dependabot[bot])
Bump svelte-sonner from 1.1.1 to 1.2.1 β 39ce639ebe506fb4b825fd08335a98bc55a7efd1 (#3670) (@dependabot[bot])
Bump @xyflow/svelte from 1.6.2 to 1.6.3 β a59e1e8cdc38513921dc01c4e686581e208fd10d (#3668) (@dependabot[bot])
Bump charm.land/lipgloss/v2 from 2.0.5 to 2.0.6 in the CLI β 98f5cac2359a4b5dd42355b9c4da24ebc1a1739d (#3662) (@dependabot[bot])
Bump @codemirror/view from 6.43.8 to 6.43.9 β f2f34fac879a920afa772c0a6f0b509b7a74c478 (#3664) (@dependabot[bot])
Bump the AWS SDK for Go v2 dependency group with five updates in the backend β ffc1f128f487d1942f56c636c1daeba757649e57 (#3731) (@dependabot[bot])
Bump github.com/samber/slog-echo/v2 from 2.0.0 to 2.1.0 in the backend β 6c3f58f2b29acfb341d2071857e089b68f69529d (#3735) (@dependabot[bot])
Bump go.getarcane.app/acfs from 0.4.1 to 0.4.2 in the CLI and backend β 65b97153f05e20107ca04c70c60f3c1210409ac3 (#3722), 8087a444b343b9e8099df3a40d3a6fbb67c85441 (#3732) (@dependabot[bot])
Bump github.com/mattn/go-runewidth from 0.0.27 to 0.0.28 in the CLI β 3f43202a9c7550d087f60077a53ae59616b925f7 (#3719) (@dependabot[bot])
Bump go.getarcane.app/updater from 0.7.2 to 0.7.3 in the backend β d9b58268878a9a3de48013a6aa6d1f2b1681112b (#3733) (@dependabot[bot])
Bump go.getarcane.app/docker/convert from 0.1.0 to 0.2.0 in the backend β 8d52e7a704f675fcc01a31a72b29b9a8e5799011 (#3734) (@dependabot[bot])
Bump charm.land/bubbletea/v2 from 2.0.8 to 2.0.9 in the CLI β f012dbf16a2473a78fa9c44e6b2e7c384e522679 (#3720) (@dependabot[bot])
Bump charm.land/bubbles/v2 from 2.1.1 to 2.2.0 in the CLI β 29c5dc6afd682d08a26185ec5aa07a88e17ac6f9 (#3721) (@dependabot[bot])
Bump @tanstack/svelte-query from 6.1.38 to 6.1.39 β d200e9f73555d23b26a7e80270283fa3a9302213 (#3725) (@dependabot[bot])
Bump bits-ui from 2.18.1 to 2.19.0 β 3646524258861b2f6d67f7bd67be4b96a830e0c0 (#3728) (@dependabot[bot])
Bump marked from 18.0.9 to 18.0.10 β 82a2771040785fd68d44d1c66d8691543b3c4d7a (#3729) (@dependabot[bot])
Bump vite-plus to 0.3.0 β f3002cbd30db67f0bd4e05feaf9dec830b1b35a3 (@kmendell)
Bump @tanstack/virtual-core from 3.17.7 to 3.17.8 β ea1ab4b086e857166bdff9f43fabb92f7cdb7360 (#3723) (@dependabot[bot])
This is a security release to address a range of vulnerabilities:
Users could update attachments on pages they did not have permission to update.
Request endpoints for drawings could be misused to create cross-site-scripting scenarios.
Draft page endpoints could be misused to alter non-draft pages without needing edit permission for those pages.
Draft pages created by other users could appear in certain search result lists.
ZIP imports with certain content could lead to a remote-code-execution scenario.
Page visibility rules may not be updated in certain recycle-bin-related scenarios.
Updating is generally advised, but strongly so where untrusted users have general access to the instance.
If untrusted users do have access, especially edit level access, it's advised to double check image upload folders to ensure there's no unexpected non-image content.
On a typical Linux-based system installation, this could be done using the find command from the BookStack installation folder like so:
# Check the general "public" server space
find ./public/uploads -type f !\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.avif" -o -iname ".gitignore" -o -iname ".htaccess"\)# Check the internal image storage space
find ./storage/uploads/images -type f !\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.avif"\)
A big thanks to the following researchers for responsibly reporting vulnerabilities which were addressed in this release:
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076) exists() now throws when the lookup itself fails, for example on a timeout, a connection error or rejected credentials, instead of also reporting false. Callers that relied on a false result for any failure need to handle the error. Note that S3 answers 403 rather than 404 for a missing object when the credentials cannot list the bucket, so granting s3:ListBucket is needed to keep getting a clean "missing" answer.
Fixed "Update Items" and "Delete Items" operations affecting every item in a collection when given an empty or missing key or query (#27759) Nothing to target is a no-op
"Update Items" and "Delete Items" operations now return null instead of falling back to every item whenever the configuration doesn't target anything β that is, when key is empty or missing (e.g. [], "") and query is empty or missing (e.g. {}). "Update Items" additionally returns null when there is nothing to write, i.e. an empty or missing payload (e.g. {}, or [] for a batch payload). Flows that relied on the previous fallback to every item can use {"limit": -1}.
Contradictory options error
"Update Items" and "Delete Items" operations now throw an error when both key and query are defined. "Update Items" also throws when key or query is combined with a batch payload.
Updated ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION to match ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION (6000 px) (#28111)
The default maximum output dimension is now 6000 px. Users who rely on the previous limit of 3000 px can explicitly configure ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION.
Used the pm2 bundled with @directus/api in the Docker images instead of installing a separate copy, so its dependencies follow the versions pinned by the workspace (#28120)
If you extend the Docker image: it now boots via CMD ["node", "docker-entrypoint.cjs"], which runs the same bootstrap then pm2-runtime sequence as before. pm2-runtime is no longer on the PATH, so a custom CMD that called it directly should hand off to docker-entrypoint.cjs instead. pm2 itself remains on the PATH for docker exec diagnostics.
@directus/api
Fixed "Update Items" and "Delete Items" operations affecting every item in a collection when given an empty or missing key or query (#27759 by @ComfortablyCoding)
@directus/storage-driver-cloudinary
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
@directus/storage-driver-s3
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
@directus/storage-driver-local
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
@directus/storage-driver-supabase
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
@directus/sdk
Updated outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users (#27945 by @kheiner)
β¨ New Features & Improvements
@directus/app
Added search-first AI tool discovery for chat and MCP tools, with schema pinned as a root chat tool. (#27797 by @bryantgillespie)
Added a caption field to the WYSIWYG image drawer, which wraps the image in a figure with a figcaption (#28026 by @alvarosabu)
Added the collection name appended to display template in item and drawer headers (#28078 by @AlexGaillard)
@directus/api
Added search-first AI tool discovery for chat and MCP tools, with schema pinned as a root chat tool. (#27797 by @bryantgillespie)
@directus/cli
Introduced @directus/cli (d6s / directus-cli) β a client-side CLI that syncs schema and configuration between Directus instances through committed JSON files, with sync pull, sync diff, sync push, and an interactive wizard (#27861 by @bryantgillespie)
@directus/types
Updated outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users (#27945 by @kheiner)
Removed dead βSave and Quitβ dropdown row outside the content item view (#28051 by @robluton)
Fixed relational items with unsaved nested values, such as newly added translated items in a content version, rendering as -- instead of their display template (#28010 by @alvarosabu)
Fixed the repeater interface options showing empty sub-fields, and dropping their key and type on save, when the sub-fields were created through the API without repeating the key and type inside their meta (#28041 by @lazerg)
Fixed relational fields showing stale values after a manual flow updated them (#28056 by @AlexGaillard)
Fixed the Markdown interface's Edit and Preview buttons not indicating which view is currently active (#28023 by @Aniket-a14)
Fixed silent failure of dragging & dropping files with an unrecognized extension into the file library (#28093 by @alvarosabu)
Fixed a request for a non-existent item when opening an item whose Many-to-One field references an unsaved parent (#27975 by @sourav-18)
Updated outdated type definitions for directus_files, directus_collections, directus_deployments, directus_settings, and directus_users (#27945 by @kheiner)
Fixed field configuration appearing to close when selecting related collection that switches interface (#28118 by @robluton)
Fixed the translations interface AI translation button only showing for admins (#28089 by @AlexGaillard)
Fixed SSO login redirecting to the last visited page instead of the originally requested page (#28080 by @AlexGaillard)
Stopped the policy creation modal from writing app access permission rows to the database, matching the policy detail page where app access permissions are applied at runtime instead of stored (#28101 by @alvarosabu)
Added block-level custom formats to the WYSIWYG interface, so block, selector and items entries in the Custom Formats option apply classes and attributes to paragraphs, headings and other block nodes from the Formats dropdown (#28044 by @alvarosabu)
Fixed WYSIWYG content the editor can't represent being hidden and unrestorable in the comparison modal (#28067 by @alvarosabu)
@directus/api
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
Added a batch-import regression test pinning that a negative temporary key maps like any other non-existent auto-increment key in merge mode (#27861 by @bryantgillespie)
Updated MCP tool descriptions and safety annotations for connector clients. (#28090 by @bryantgillespie)
Improved MS SQL Server reliability and performance by optimizing schema introspection and only enabling trigger compatibility when required (#27699 by @br41nslug)
Updated various dependencies to address CVEs (#28110 by @br41nslug)
Fixed slow extension sync from remote storage during startup. Added EXTENSIONS_STORAGE_MAX_CONCURRENCY to configure the maximum number of concurrent requests to the extensions storage location (#27989 by @dstockton)
Updated ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION to match ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION (6000 px) (#28111 by @ComfortablyCoding)
Fixed TranslationsService.updateMany incorrectly rejecting single-row updates containing both key and language (#28001 by @suhailopensource)
Fixed collection names with surrounding whitespace being accepted on creation (#28038 by @lazerg)
Fixed WebSocket rate limiting breaking on shared Redis setups where keys must start with a per-project prefix. The WebSocket limiter now accepts RATE_LIMITER_WEBSOCKETS_* values as overrides, including RATE_LIMITER_WEBSOCKETS_KEY_PREFIX to override the Redis key prefix. (#28107 by @AlexGaillard)
@directus/storage-driver-azure
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
@directus/storage-driver-gcs
Fixed storage connections leaking when asset requests were cancelled or a transformation failed, which eventually made every asset request return a permission error until Directus was restarted (#28076 by @dstockton)
Improved MS SQL Server reliability and performance by optimizing schema introspection and only enabling trigger compatibility when required (#27699 by @br41nslug)
@directus/env
Fixed slow extension sync from remote storage during startup. Added EXTENSIONS_STORAGE_MAX_CONCURRENCY to configure the maximum number of concurrent requests to the extensions storage location (#27989 by @dstockton)
Updated ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION to match ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION (6000 px) (#28111 by @ComfortablyCoding)
Updated ESLint dependencies eslint, @eslint/js, eslint-plugin-vue, and typescript-eslint. Replaced eslint-plugin-import with eslint-plugin-import-x (#28047 by @br41nslug)
up2k: client could waste a little bandwidth while recovering from a network glitch 18791c5
if PRTY_CONFIG is set to a config-file that is also autodetected, then explain the misconfiguration instead of crashing like before 14e2d79
wopi: fix session-timeout hint to clients (thx @kamaeff!) 92c3f32
js: fix chance of duplicate prologue on very first page visit eeb399e
js: fix panic on image dragdrop out of the browser window dcc0abd
π§ other changes
up2k: client now detects when server or reverseproxy is incorrectly configured with an impractically small request-body-size-limit, crashing the website with an explanation how to fix it f19ef03
also allows setting the chunksize all the way down to 1 megabyte when absolutely necessary (bad idea, slow)
shares: harden single-file shares some more 21c2c729ff6a71
just removing footguns (motivated by a bug-report that was a false-positive)
copyparty.exe: upgrade to python 3.14.7 from 3.13.14 8b6e897
larger and slightly faster (compensated for the size bloat by making the text-image-generator more shitty)
π fun facts
the thumbex example is also a cool example how relevant the "pseudo" in PRNG can be; with random.randrange instead of os.urandom, first run followed by restarting copyparty and another run...heh