users-permissions: move server code into server/src (#26105)
π Enhancement
content-type-builder: support required on relation attributes (#27080)
core: look models up on the registries in getModel (#27143)
database: reduce per-column work when mapping rows to entities (#27144)
β οΈ Changes to be aware of
Filter operators: literal wildcards and true case-insensitive equality
$eqi / $nei now do real case-insensitive equality (= LOWER(?)), not LIKE, so values with %, _, or a trailing \ no longer act as wildcards or crash some databases. Substring operators ($contains, $startsWith, $endsWith, and case-insensitive variants) now treat %, _, and \ in the filter value as literal characters. If you relied on % / _ inside those filters as SQL wildcards, update filters to match the new literal semantics.
(#26476)
deps: upgrade handlebars, axios, tar, and related transitive deps (#27091)
deps: bump @radix-ui/react-toolbar from 1.0.4 to 1.1.11 (#27059)
email-nodemailer: migrate unit tests from jest to vitest (#27074)
email-sendmail: migrate unit tests from jest to vitest (#27075)
upload-local: migrate unit tests from jest to vitest (#27073)
β οΈ Changes to be aware of
Required media and relations: opt-in strictRelations
New config api.documents.strictRelations enforces required media and relations on publish (drafts can still be empty). On by default for new projects; existing apps are unchanged until you set it. To opt in, set documents.strictRelations: true in config/api.
(#27028)
Empty multiple media / morphMany now returns []
Populated empty morphMany relations (including type: 'media', multiple: true) serialize as [] instead of null, matching other to-many relations. This is unconditional and not gated by strictRelations. If clients, webhooks, or integrations check field === null for empty galleries / morphMany, treat [] as empty instead (e.g. !field?.length).
(#27090)
typescript-utils: bump internal deps to 5.50.1 (#26946)
β οΈ Changes to be aware of
Admin auth cookie name
You can set admin.auth.cookie.name in admin config to rename the access-token cookie (default remains jwtToken). Useful when another app on a shared parent domain sets a jwtToken cookie and breaks admin login.
In v5, status is reserved for draft/published filtering. If a content type has Draft & Publish enabled and a custom status field, Strapi now logs a startup warning instead of failing boot. The Content-Type Builder still blocks adding status or enabling D&P when status already exists.
@strapi/upgrade now warns and offers to pin ranged @strapi/* dependencies (e.g. ^5.50.0) before upgrading, so upgrades don't silently report "already up-to-date" when node_modules resolved ahead of package.json.
Save a draft with Cmd/Ctrl+Enter (or Cmd/Ctrl+S). Publish with Cmd/Ctrl+Shift+Enter. Since v5.31.3, plain Cmd/Ctrl+Enter published immediately β that shortcut now saves instead. (#26621)
β οΈ Note: This is the final Strapi 4 release β οΈ
No further updates to Strapi 4 will be published, this release serves as the final version of Strapi 4 which is considered EOL (End-Of-Life) as of April 30th, 2026. All Strapi users should migrate to Strapi 5: https://docs.strapi.io/cms/migration/v4-to-v5/introduction-and-faq
Also please note, this does include Strapi Customers as well. Strapi Cloud will still continue to function with Strapi 4 but that may be subject change in the near future without warning.
What's Changed
Security
Fixed a critical vulnerability where relational filtering could expose sensitive data through insufficient query sanitization. See GHSA-rjg2-95x7-8qmx / CVE-2026-27886.
Upgraded tar to v7 to address security warnings.
Applied v4 dependency security and maintenance updates.
Fixes
Enforced unique admin email validation when updating the authenticated user profile.
Content types with attributes named filters, sort, fields, or populate no longer cause 400 validation errors on populate queries and countDraftRelations (#21338, #25762)
check devDependencies when resolving required admin deps (#22130)