Strapi v5 Plugin API: Breaking Changes#
Overview#
Strapi v5 removed the @strapi/helper-plugin package entirely and replaced it with exports spread across @strapi/strapi/admin and @strapi/design-system. Any plugin or custom admin code that still imports from @strapi/helper-plugin will crash the admin panel at runtime. The most visible symptom is TypeError: checkUserHasPermissions is not a function, caused by the useRBAC hook trying to call a function that no longer exists in the expected location.
Key breaking changes affecting plugin developers:
@strapi/helper-pluginremoved — all ~50 exports relocated or deleted. (breaking change doc)useRBAChook signature changed — argument format changed from an object to an array. (RBAC breaking change doc)content-manager_rbacManagerredux store section removed — the regular permissions system replaces it.useRBACProviderremoved — replaced by theuseAuthhook.
useRBAC: Signature Change#
The useRBAC hook is now imported from @strapi/strapi/admin (not @strapi/helper-plugin) and its first argument changed from a named-key object to a flat array of permissions.
| v4 | v5 | |
|---|---|---|
| Import | @strapi/helper-plugin | @strapi/strapi/admin |
| Argument | { main: [{ action: '...' }] } | [{ action: '...' }] |
allowedActions keys | derived from the object key (canMain) | derived from the last permission action segment (canMain) |
Passing an object still works in v5 but logs a deprecation warning: "useRBAC: The first argument should be an array of permissions, not an object. This will be deprecated in the future."
The hook signature in v5: useRBAC(permissionsToCheck, passedPermissions?, rawQueryContext?). Action names are derived from the last dot-separated segment, with hyphens removed and CamelCased — e.g. admin::roles.create-draft → canCreateDraft.
Internally, useRBAC retrieves checkUserHasPermissions via useAuth selector and calls it inside a useEffect . If the Auth context is not initialized — for example, because an old plugin is rendering outside the v5 provider tree — checkUserHasPermissions is undefined and the crash occurs.
checkUserHasPermissions and the Auth Context#
In v5, checkUserHasPermissions lives in the Auth context, defined in packages/core/admin/admin/src/features/Auth.tsx. It is a useCallback that:
- Short-circuits if
permissionsis empty. - Filters the current user's permissions against the requested ones by
actionand optionallysubject. - Runs them through the RBAC middleware (supports custom
rawQueryContext). - If conditions are present, validates against the backend API; otherwise returns immediately.
To access checkUserHasPermissions directly (replacing the removed hasPermissions util from helper-plugin):
import { useAuth } from '@strapi/strapi/admin';
const { checkUserHasPermissions } = useAuth(
'COMPONENT_NAME',
(state) => state.checkUserHasPermissions
);
Migration Map: Key helper-plugin Exports#
Full reference: Helper-plugin migration guide
v4 (@strapi/helper-plugin) | v5 destination | Notes |
|---|---|---|
useRBAC | @strapi/strapi/admin | Signature changed (array, not object) |
useRBACProvider | removed | Use useAuth from @strapi/strapi/admin |
hasPermissions | removed | Use checkUserHasPermissions via useAuth |
CheckPagePermissions | Page.Protect in @strapi/strapi/admin | Behavior change: shows NoPermissions instead of redirecting |
CheckPermissions | removed | Use useRBAC or Page.Protect |
useNotification | useNotification in @strapi/strapi/admin | Return type changed; warning → danger |
useFetchClient / getFetchClient | @strapi/strapi/admin | Same name, new import |
useQueryParams | @strapi/strapi/admin | Same name, new import |
useAPIErrorHandler | @strapi/strapi/admin | Same name, new import |
translatedErrors | @strapi/strapi/admin | Same name, new import |
useCMEditViewDataManager | unstable_useContentManagerContext in @strapi/strapi/admin | Renamed and marked unstable |
DateTimePicker, Status | @strapi/design-system | Design system re-exports |
useCallbackRef, useCollator, useFilter | @strapi/design-system | Design system re-exports |
AnErrorOccurred | Page.Error in @strapi/strapi/admin | — |
LoadingIndicatorPage | Page.Loading in @strapi/strapi/admin | — |
GuidedTour | useGuidedTour hook in @strapi/admin | Redux store structure changed; plugins reading old store crash |
The v5 upgrade tool includes a deprecate-helper-plugin codemod that handles a subset of these changes automatically , but many require manual migration.
Diagnosing and Fixing the Crash#
Symptom: Admin panel crashes with TypeError: checkUserHasPermissions is not a function or Cannot read properties of undefined (reading 'tours').
Root cause: A plugin (custom or third-party) still imports from @strapi/helper-plugin or uses the v4 useRBAC object-argument syntax.
Diagnosis steps:
-
Search installed plugins for deprecated imports:
grep -r "helper-plugin" ./node_modules --include="package.json" -l grep -r "from '@strapi/helper-plugin'" ./src -l -
Check third-party plugins for v5 compatibility notes in their changelogs.
-
If no plugins are found, the error may be a version-specific bug — it was reproduced in v5.31.3 and resolved in v5.34.0.
Fix:
- Migrate all imports per the helper-plugin migration reference.
- Update
useRBACcalls from object-argument to array-argument format. - Replace
useRBACProviderwithuseAuth. - Run codemods via
npx @strapi/upgrade@latest 5.0.0then audit remaining manual changes. - After updating, clean and rebuild:
rm -rf .cache build dist node_modules && npm install && npm run build
Key source files:
useRBAChook —packages/core/admin/admin/src/hooks/useRBAC.tsAuth.tsx(checkUserHasPermissions) —packages/core/admin/admin/src/features/Auth.tsx- deprecate-helper-plugin codemod