Migrating from 4.x.x to 5.x.x
Motivation Behind the Releaseβ
Refine v5 removes deprecated APIs and legacy systems, upgrades to TanStack Query v5, and adds React 19 support. The result is a cleaner, faster codebase with better developer experience.
Before upgrading to Refine 5, your project must first be migrated from Refine 3.x.x to 4.x.x. This is an essential step, as Refine 5 builds upon the changes introduced in version 4.
β Please refer to the migration guide for details on upgrading from 3.x.x to 4.x.x
Once your project is on Refine 4.x.x, you can proceed with the upgrade to Refine 5.x.x using the steps below.
Migration Steps
- Step 1: Upgrade dependencies
- Step 2: Remove deprecated APIs
- Step 3: Update router provider
- Step 4: Update auth provider
- Step 5: Upgrade TanStack Query
- Step 6: Optional: Upgrade React
1. Upgrade All Refine Dependencies to v5β
Package Version Changesβ
All Refine packages have been bumped to the next major version as a coordinated release. This ensures maximum stability and compatibility when using packages together - all Refine v5 packages are tested as a complete ecosystem.
Package | v4 Version | v5 Version |
---|---|---|
@refinedev/core | 4.x.x | 5.x.x |
react | 17 or 18 | 18 or 19 |
TanStack React Query | 4.x.x | 5.x.x |
@refinedev/antd | 5.x.x | 6.x.x |
@refinedev/mui | 6.x.x | 7.x.x |
@refinedev/mantine | 2.x.x | 3.x.x |
@refinedev/chakra-ui | 2.x.x | 3.x.x |
@refinedev/react-hook-form | 4.x.x | 5.x.x |
@refinedev/react-table | 5.x.x | 6.x.x |
@refinedev/react-router | 1.x.x | 2.x.x |
@refinedev/nextjs-router | 6.x.x | 7.x.x |
@refinedev/remix-router | 3.x.x | 4.x.x |
@refinedev/inferencer | 5.x.x | 6.x.x |
@refinedev/devtools | 1.x.x | 2.x.x |
- Update with Refine CLI
- Manual Update
refine-cli
β‘οΈ You can easily update Refine packages with the Refine CLI update
command.
npm run refine update
manual
You need to update all @refinedev/*
packages to their compatible v5 versions. Use the version table above to find the correct version for each package you're using in your project.
Core packages (required):
npm i @refinedev/core@^5.0.0 @tanstack/react-query@^5.0.0
UI library packages (choose based on what you're using):
# If using Ant Design
npm i @refinedev/antd@^6.0.0
# If using Material-UI
npm i @refinedev/mui@^7.0.0
# If using Mantine
npm i @refinedev/mantine@^3.0.0
# If using Chakra UI
npm i @refinedev/chakra-ui@^3.0.0
Router packages (choose based on your router):
# If using React Router
npm i @refinedev/react-router@^2.0.0
# If using Next.js
npm i @refinedev/nextjs-router@^7.0.0
# If using Remix
npm i @refinedev/remix-router@^4.0.0
Additional packages (if you're using them):
# Form handling
npm i @refinedev/react-hook-form@^5.0.0
# Table handling
npm i @refinedev/react-table@^6.0.0
# Data providers (update the ones you use)
npm i @refinedev/simple-rest@^5.0.0
npm i @refinedev/graphql@^6.0.0
npm i @refinedev/strapi-v4@^5.0.0
npm i @refinedev/supabase@^5.0.0
# ... and others based on your data provider
Example for a complete Ant Design project:
npm i @refinedev/core@^5.0.0 @refinedev/antd@^6.0.0 @refinedev/react-router@^2.0.0 @refinedev/simple-rest@^5.0.0 @tanstack/react-query@^5.0.0
Once dependencies are updated, proceed with the following breaking changes:
2. Remove All Deprecated APIs from Refine v4β
All deprecated APIs marked for removal in v4 have been completely removed in v5.
- β¨ Refine Codemod
- Manual Update
codemod
πͺ Migrating your project automatically with refine-codemod β¨ (recommended)
The @refinedev/codemod
package handles the breaking changes for your project and automatically migrates it from 4.x.x
to 5.x.x
.
Simply cd
into the root folder of your project (where the package.json
is located) and run this command:
npx @refinedev/codemod@latest refine4-to-refine5
π¨ The refine4-to-refine5 codemod only fixes APIs deprecated or removed in Refine@4. It does not handle items deprecated during the Refine@3β4 migration. For those, run the refine3-to-refine4 codemod first.
β οΈ Changes not handled by the codemod
Unfortunately, the codemod cannot cover every case. While it automates most of the migration, some changes still require manual updates. Below is the list of removed or modified APIs that you'll need to adjust yourself.
useNavigation β useGo
π¨ Affects: Navigation helpers (push
, replace
, goBack
)
The return values from useNavigation
have been removed. You should now use useGo
for navigation:
- import { useNavigation } from "@refinedev/core";
+ import { useGo } from "@refinedev/core";
- const { replace, push } = useNavigation();
- replace("/tasks/new");
+ const go = useGo();
+ go({ to: "/tasks/new", type: "replace" });
+ go({ to: "/tasks/new", type: "push" });
For backward navigation (goBack
), use your routerβs native API instead.
- import { useNavigation } from "@refinedev/core";
+ import { useNavigate } from "react-router";
- const { goBack } = useNavigation();
+ const navigate = useNavigate();
- goBack();
+ navigate(-1);
ITreeMenu β TreeMenuItem & list field changes
π¨ Affects: useMenu
, custom sider renderers
ITreeMenu
has been removed β useTreeMenuItem
instead (codemod updates this).list
is now always a string route. πlist.path
is gone andlist
is no longer a function.
Why:
Previously, you could define a React component in the <Refine />
resource as list
. This is no longer supported. Routes/components must be defined in your router. Because of this, list
is now just a route string, not a function or object with path
.
- const { menuItems, selectedKey } = useMenu();
- menuItems.map((item: ITreeMenu) => {
- const { key, list } = item;
- const route =
- typeof list === "string"
- ? list
- : typeof list !== "function"
- ? list?.path
- : key;
- });
+ const { menuItems, selectedKey } = useMenu();
+ menuItems.map((item: TreeMenuItem) => {
+ const { list } = item;
+ const route = list ?? key; // always a string route now
+ });
manual
If youβd like to migrate manually, or if the codemod didnβt cover all of your cases, check the full list of breaking changes with before/after examples.
3. Refactor Legacy Router Provider to use new Router Providerβ
If your project is still using the legacyRouterProvider
provider, you'll need to migrate to the new router system. The new router provider offers greater flexibility and better integration with modern routing patterns.
Please refer these guides to refactor your project:
4. Refactor Legacy Auth Provider to use new Auth Providerβ
If your project is still using the legacy auth provider legacyAuthProvider
or auth hooks with v3LegacyAuthProviderCompatible: true
, you must migrate to the modern auth provider structure because these are completely removed.
For complete migration instructions, please refer to the Auth Provider Migration Guide.
useLogin({
- v3LegacyAuthProviderCompatible: true,
});
<Refine
- legacyAuthProvider={legacyAuthProvider}
+ authProvider={authProvider}
/>
5. Upgrade TanStack Query to v5β
You'll need to upgrade TanStack Query from v4 to v5. Please refer to the TanStack Query migration guide for detailed instructions on this upgrade.
6. Upgrade React to v19 (optional)β
Refine v5 supports both React 18 and React 19. If you want to take advantage of the latest React features, you can optionally upgrade to React 19. Please refer to the React 19 release notes for more information about the new features and migration considerations.
List of All Breaking Changesβ
If you prefer to migrate manually or the codemod didn't handle all your use cases, you can follow this comprehensive guide to update your codebase step by step. Each section below covers a specific breaking change with before/after examples.
metaData β metaβ
π¨ Affects: All data hooks, useForm, useTable, useDataGrid, useSelect, etc.
The metaData
parameter has been renamed to meta
across all hooks:
useList({
- metaData: { foo: "bar" },
+ meta: { foo: "bar" },
})
useOne({
- metaData: { headers: { "Authorization": "Bearer token" } },
+ meta: { headers: { "Authorization": "Bearer token" } },
})
useCreate({
- metaData: { endpoint: "custom" },
+ meta: { endpoint: "custom" },
})
AuthBindings β AuthProvider (Type Imports)β
π¨ Affects: Type imports from @refinedev/core
Type interfaces have been renamed in @refinedev/core. When importing these types, you'll need to update the import names while preserving usage with aliases:
// AuthBindings β AuthProvider
- import { type AuthBindings } from "@refinedev/core";
+ import { type AuthProvider } from "@refinedev/core";
RouterBindings β RouterProvider (Type Imports)β
π¨ Affects: Type imports from @refinedev/core
Type interfaces have been renamed in @refinedev/core. When importing these types, you'll need to update the import names while preserving usage with aliases:
- import type { RouterBindings } from "@refinedev/core";
+ import type { RouterProvider } from "@refinedev/core";
sorter/sort β sortersβ
π¨ Affects: useList, useInfiniteList, useTable, useDataGrid, useSelect
The sorter
and sort
parameters have been renamed to sorters
:
useList({
- sort: [{ field: "title", order: "asc" }],
+ sorters: [{ field: "title", order: "asc" }],
})
useTable({
- initialSorter: [{ field: "createdAt", order: "desc" }],
+ sorters: {
+ initial: [{ field: "createdAt", order: "desc" }]
+ },
})
filters Updatesβ
π¨ Affects: useList, useTable, useDataGrid, useSelect
Filter configuration has been simplified and moved out of config objects:
useList({
- config: {
- filters: [{ field: "status", operator: "eq", value: "published" }],
- },
+ filters: [{ field: "status", operator: "eq", value: "published" }],
})
useTable({
- initialFilter: [{ field: "category", operator: "eq", value: "tech" }],
- permanentFilter: [{ field: "status", operator: "eq", value: "active" }],
+ filters: {
+ initial: [{ field: "category", operator: "eq", value: "tech" }],
+ permanent: [{ field: "status", operator: "eq", value: "active" }]
+ },
})
pagination Updatesβ
π¨ Affects: useList, useTable, useDataGrid, useSelect
Pagination configuration has been restructured:
useList({
- hasPagination: false,
+ pagination: { mode: "off" },
})
useTable({
- initialCurrent: 1,
- initialPageSize: 20,
- hasPagination: false,
+ pagination: { mode: "off", currentPage: 1, pageSize: 20 },
})
####Β pagination.current -> pagination.currentPage
π¨ Affects: useTable, useDataGrid, useSimpleList, useSubscription, useList, useCheckboxGroup, useSelect
useTable({
- pagination: { current: 1 },
+ pagination: { currentPage: 1 },
})
####Β setCurrent -> setCurrentPage
π¨ Affects: useTable, useDataGrid, useSimpleList
The setCurrent
function has been renamed to setCurrentPage
:
const {
- setCurrent,
- current,
+ currentPage,
+ setCurrentPage,
} = useTable();
Resource options β metaβ
π¨ Affects: Resource definitions in <Refine>
component
Resource options
have been renamed to meta
:
<Refine
resources={[
{
name: "posts",
- options: { label: "Blog Posts" },
+ meta: { label: "Blog Posts" },
},
]}
/>
resourceName/resourceNameOrRouteName β resourceβ
π¨ Affects: useImport, useExport, All Button components
useImport({
- resourceName: "posts",
+ resource: "posts",
})
<CreateButton
- resourceNameOrRouteName="posts"
+ resource="posts"
/>
config Object Removalβ
π¨ Affects: useList, useInfiniteList
The config parameter has been flattened in data hooks:
useList({
- config: {
- pagination: { currentPage: 1, pageSize: 10 },
- sorters: [{ field: "title", order: "asc" }],
- filters: [{ field: "status", operator: "eq", value: "published" }],
- hasPagination: false,
- sort: [{ field: "title", order: "asc" }],
- metaData: { foo: "bar" },
- },
+ pagination: { currentPage: 1, pageSize: 10, mode: "off" },
+ sorters: [{ field: "title", order: "asc" }],
+ filters: [{ field: "status", operator: "eq", value: "published" }],
+ meta: { foo: "bar" },
})
useTable Hook Restructuringβ
π¨ Affects: useTable, useSimpleList, useDataGrid
The useTable
hook and its UI variants (useDataGrid
from @refinedev/mui, useSimpleList
) have been significantly restructured:
useTable({
- initialCurrent: 1,
- initialPageSize: 10,
- hasPagination: false,
+ pagination: { currentPage: 1, pageSize: 10 , mode: "off" },
- setCurrent,
+ setCurrentPage,
- initialSorter: [{ field: "title", order: "asc" }],
- permanentSorter: [{ field: "status", order: "asc" }],
+ sorters: {
+ initial: [{ field: "title", order: "asc" }],
+ permanent: [{ field: "status", order: "asc" }]
+ },
- initialFilter: [{ field: "status", operator: "eq", value: "published" }],
- permanentFilter: [{ field: "category", operator: "eq", value: "tech" }],
- defaultSetFilterBehavior: "replace",
+ filters: {
+ initial: [{ field: "status", operator: "eq", value: "published" }],
+ permanent: [{ field: "category", operator: "eq", value: "tech" }],
+ defaultBehavior: "replace"
+ },
})
// Return values also changed
const {
- sorter,
- setSorter,
- tableQueryResult,
- current,
+ currentPage,
+ sorters,
+ setSorters,
+ tableQuery,
} = useTable();
queryResult β queryβ
π¨ Affects: useForm, useSelect, useShow, useSimpleList, useMany
const {
- queryResult,
+ query,
} = useShow();
const {
- queryResult,
+ query,
} = useForm();
defaultValueQueryResult β defaultValueQueryβ
π¨ Affects: useSelect
const {
- defaultValueQueryResult,
+ defaultValueQuery,
} = useSelect();
tableQueryResult β tableQueryβ
π¨ Affects: useTable, useDataGrid
const {
- tableQueryResult,
+ tableQuery,
} = useTable();
mutationResult β mutationβ
π¨ Affects: useCreate, useUpdate, useDelete, useCreateMany, useUpdateMany, useDeleteMany, useCustomMutation
const {
- mutationResult,
+ mutation,
} = useForm();
isLoading β isPendingβ
π¨ Affects: useCreate, useUpdate, useDelete, useCreateMany, useUpdateMany, useDeleteMany, useCustomMutation
For mutation hooks, the loading state property has been updated:
const { mutate, isPending } = useCreate();
- if (isLoading) return <Spinner />;
+ if (isPending) return <Spinner />;
useNavigation β useGo, useBackβ
The useNavigation
hook has been replaced with individual hooks:
- import { useNavigation } from "@refinedev/core";
+ import { useGo, useBack } from "@refinedev/core";
const MyComponent = () => {
- const { push, goBack, replace } = useNavigation();
+ const go = useGo();
+ const back = useBack();
- push("/posts");
+ go({ to: "/posts" });
- goBack();
+ back();
- replace("/posts");
+ go({ to: "/posts", type: "replace" });
};
useResource β useResourceParamsβ
The useResource
hook has been removed in favor of useResourceParams
. The new useResourceParams
hook offers the same functionality as useResource
, while introducing additional features and a more streamlined API. To reduce confusion and improve consistency, all resource-related logic should now use useResourceParams
exclusively.
- import { useResource } from "@refinedev/core";
+ import { useResourceParams } from "@refinedev/core";
- useResource("posts");
+ useResourceParams({ resource: "posts" });
ignoreAccessControlProvider β accessControlβ
<CreateButton
- ignoreAccessControlProvider
+ accessControl={{ enabled: false }}
- resourceNameOrRouteName="posts"
+ resource="posts"
/>
Resource options β metaβ
The options
prop has been moved to meta
:
<Refine
resources={[
{
name: "posts",
- options: {
- label: "Blog Posts",
- icon: <PostIcon />,
- route: "my-posts",
- auditLog: {
- permissions: ["list", "create"],
- },
- hide: false,
- dataProviderName: "default",
- },
- canDelete: true,
+ meta: {
+ label: "Blog Posts",
+ icon: <PostIcon />,
+ parent: "categories",
+ canDelete: true,
+ audit: ["list", "create"],
+ hide: false,
+ dataProviderName: "default",
+ },
},
]}
/>
DataProvider getList and custom Method Updatesβ
export const dataProvider = {
getList: ({
resource,
pagination: {
+ mode: "off" | "server" | "client",
},
- hasPagination,
+ sorters,
- sort,
filters,
+ meta,
- metaData,
}) => {
// ...
},
custom: ({
// ...
+ sorters,
- sort,
}) => {
// ...
},
};
useImport and useExport Hook Updatesβ
The useImport
and useExport
hooks have additional parameter updates:
useImport({
- resourceName: "posts",
+ resource: "posts",
- metaData: { foo: "bar" },
+ meta: { foo: "bar" },
// These are now used as direct props instead of nested config
- mapData: (item) => item,
- paparseConfig: {},
- batchSize: 1000,
+ mapData: (item) => item,
+ paparseConfig: {},
+ batchSize: 1000,
})
useExport({
- resourceName: "posts",
+ resource: "posts",
- sorter: [{ field: "title", order: "asc" }],
+ sorters: [{ field: "title", order: "asc" }],
- metaData: { foo: "bar" },
+ meta: { foo: "bar" },
- exportOptions: {},
+ unparseConfig: {},
// These are now used as direct props
- mapData: (item) => item,
- maxItemCount: 1000,
- pageSize: 20,
+ mapData: (item) => item,
+ maxItemCount: 1000,
+ pageSize: 20,
})
queryKeys -> keysβ
π¨ Affects: Custom implementations using Refine helpers
// queryKeys helper updates
- import { queryKeys } from "@refinedev/core";
+ import { keys } from "@refinedev/core";
// Usage updates
- queryKeys.data().resource("posts").action("list").get();
+ keys().data().resource("posts").action("list").get();
useNavigation β useGoβ
π¨ Affects: Navigation helpers (push
, replace
, goBack
)
The return values from useNavigation
have been removed. You should now use useGo
for navigation:
- import { useNavigation } from "@refinedev/core";
+ import { useGo } from "@refinedev/core";
- const { replace, push } = useNavigation();
- replace("/tasks/new");
+ const go = useGo();
+ go({ to: "/tasks/new", type: "replace" });
+ go({ to: "/tasks/new", type: "push" });
For backward navigation (goBack
), use your routerβs native API instead.
- import { useNavigation } from "@refinedev/core";
+ import { useNavigate } from "react-router";
- const { goBack } = useNavigation();
+ const navigate = useNavigate();
- goBack();
+ navigate(-1);
ITreeMenu β TreeMenuItem & list field changesβ
π¨ Affects: useMenu
, custom sider renderers
ITreeMenu
has been removed β useTreeMenuItem
instead (codemod updates this).list
is now always a string route. πlist.path
is gone andlist
is no longer a function.
Why:
Previously, you could define a React component in the <Refine />
resource as list
. This is no longer supported. Routes/components must be defined in your router. Because of this, list
is now just a route string, not a function or object with path
.
- const { menuItems, selectedKey } = useMenu();
- menuItems.map((item: ITreeMenu) => {
- const { key, list } = item;
- const route =
- typeof list === "string"
- ? list
- : typeof list !== "function"
- ? list?.path
- : key;
- });
+ const { menuItems, selectedKey } = useMenu();
+ menuItems.map((item: TreeMenuItem) => {
+ const { list } = item;
+ const route = list ?? key; // always a string route now
+ });
ThemedLayoutV2 β ThemedLayoutβ
π¨ Affects: Layout components across all UI packages
The V2 layout components have been renamed to remove the V2 suffix across all UI packages (@refinedev/antd
, @refinedev/mui
, @refinedev/mantine
, @refinedev/chakra-ui
).
Components affected:
ThemedLayoutV2
βThemedLayout
ThemedTitleV2
βThemedTitle
ThemedSiderV2
βThemedSider
ThemedHeaderV2
βThemedHeader
- import { ThemedLayoutV2, ThemedTitleV2, ThemedSiderV2, ThemedHeaderV2 } from "@refinedev/antd";
+ import { ThemedLayout, ThemedTitle, ThemedSider, ThemedHeader } from "@refinedev/antd";
- Motivation Behind the Release
- 1. Upgrade All Refine Dependencies to v5
- Package Version Changes
- 2. Remove All Deprecated APIs from Refine v4
- 3. Refactor Legacy Router Provider to use new Router Provider
- 4. Refactor Legacy Auth Provider to use new Auth Provider
- 5. Upgrade TanStack Query to v5
- 6. Upgrade React to v19 (optional)
- List of All Breaking Changes
- metaData β meta
- AuthBindings β AuthProvider (Type Imports)
- RouterBindings β RouterProvider (Type Imports)
- sorter/sort β sorters
- filters Updates
- pagination Updates
- Resource options β meta
- resourceName/resourceNameOrRouteName β resource
- config Object Removal
- useTable Hook Restructuring
- queryResult β query
- defaultValueQueryResult β defaultValueQuery
- tableQueryResult β tableQuery
- mutationResult β mutation
- isLoading β isPending
- useNavigation β useGo, useBack
- useResource β useResourceParams
- ignoreAccessControlProvider β accessControl
- DataProvider getList and custom Method Updates
- useImport and useExport Hook Updates
- queryKeys -> keys
- useNavigation β useGo
- ITreeMenu β TreeMenuItem & list field changes
- ThemedLayoutV2 β ThemedLayout