Usage with Existing Projects
Integrating Refine into an existing project is as simple as installing @refinedev/core
package and importing Refine
component into your application.
Once imported, Refine
component provides necessary context to all children components for Refine hooks and components to work.
Only required prop for Refine
component is dataProvider
. You can read more about data provider here.
Quickstart
Only needed package for Refine to work is @refinedev/core
. For demonstration purposes, we will also install @refinedev/simple-rest
package to use as data provider. You can use one of our data providers or create your own.
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/simple-rest
yarn add @refinedev/core @refinedev/simple-rest
import { Refine } from "@refinedev/core";
import dataProvider from "@refinedev/simple-rest";
const API_URL = "https://api.fake-rest.refine.dev";
function App() {
return (
<ExistingProvider>
<Refine dataProvider={dataProvider(API_URL)}>
{/* You can use Refine hooks inside here */}
<ComponentWithRefineHooks />
<ExistingComponent1>
</Refine>
</ExistingProvider>
);
}
Headless Examples
The following example shows how to use Refine's useShow
hook with an existing application.
- Vite
- Next.js App
- Next.js Pages
Vite
As you can see in the example below, wrapping App.tsx
file with Refine
component is enough to use Refine hooks inside your application.
Code Example
Dependencies: @refinedev/core@latest,@refinedev/simple-rest@latest
Content: import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import { OtherComponent } from "./src/other-component"; import { RefineComponent } from "./src/refine-component"; const API_URL = "https://api.fake-rest.refine.dev"; export default function App() { return ( <> <Refine dataProvider={dataProvider(API_URL)}> {/* You can use Refine hooks here */} <OtherComponent /> <RefineComponent /> </Refine> </> ); }
Content: import { useShow } from "@refinedev/core"; export const RefineComponent = () => { const { queryResult } = useShow({ resource: "products", id: 1 }); return ( <div> <p>Hello From My Refine Component!</p> <code>{`const { queryResult } = useShow({ resource: "products", id: 1 });`}</code> <p>useShow hook queryResult:</p> <code>{JSON.stringify(queryResult.data, null, 2)}</code> </div> ); };
Content: export const OtherComponent = () => { return ( <div> <p>Hello From My Existing Component</p> <p>This component represents your existing components.</p> <hr /> </div> ); };
Next.js App
As you can see in the example below, wrapping layout.tsx
file with Refine
component is enough to use Refine hooks & components inside your application.
Code Example
Dependencies:
Content: import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; const API_URL = "https://api.fake-rest.refine.dev"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <Refine dataProvider={dataProvider(API_URL)}>{children}</Refine> </body> </html> ); }
Content: import Link from "next/link"; import { useShow } from "@refinedev/core"; export default function RefinePage() { const { queryResult } = useShow({ resource: "products", id: 1 }); return ( <div> Hello From My Refine Component! <hr /> <p>useShow hook queryResult:</p> <code>{JSON.stringify(queryResult.data, null, 2)}</code> <hr /> <Link href="/">Go to Home Page</Link> </div> ); }
Content: import Link from "next/link"; export default function Home({ data }) { return ( <div> <h1>Home Page</h1> <Link href="/other">Go to other page</Link> <br /> <Link href="/refine">Go to Refine page</Link> </div> ); }
Content: import Link from "next/link"; export default function OtherPage() { return ( <div> <h1>Hello From Other Page</h1> <Link href="/">Go to Home Page</Link> </div> ); }
Next.js Pages
As you can see in the example below, wrapping _app.tsx
file with Refine
component is enough to use Refine hooks & components inside your application.
Code Example
Dependencies:
Content: import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; const API_URL = "https://api.fake-rest.refine.dev"; export default function MyApp({ Component, pageProps }) { return ( <Refine dataProvider={dataProvider(API_URL)}> <Component {...pageProps} /> </Refine> ); }
Content: import Link from "next/link"; import { useShow } from "@refinedev/core"; export default function RefinePage() { const { queryResult } = useShow({ resource: "products", id: 1 }); return ( <div> Hello From My Refine Component! <hr /> <p>useShow hook queryResult:</p> <code>{JSON.stringify(queryResult.data, null, 2)}</code> <hr /> <Link href="/">Go to Home Page</Link> </div> ); }
Content: import Link from "next/link"; export default function Home({ data }) { return ( <div> <h1>Hello From Home</h1> <Link href="/other">Go to Other Page</Link> <br /> <Link href="/refine">Go to Refine Page</Link> </div> ); }
Content: export default function OtherPage() { return ( <div> <h1>Hello From Other Page</h1> <Link href="/">Go to Home Page</Link> </div> ); }
Router Examples
In the following examples below, we will integrate Refine into /refine
route of an existing application.
See the Routing Guide for more information.
- React Router
- Next.js App
- Next.js Pages
React Router
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/react-router-v6 @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/react-router-v6 @refinedev/simple-rest
yarn add @refinedev/core @refinedev/react-router-v6 @refinedev/simple-rest
We start by creating
RefineContext
component inrefine/refine-context.tsx
file. This file will be used to wrap/refine
routes of our application.And then in
App.tsx
file, we are adding a newRoute
component withpath="/refine"
and wrapping it withRefineContext
component.Finally, we create
refine/pages/products/list.tsx
file, here we can use Refine features, since it's layout is wrapped withRefine
component.
Code Example
Dependencies: @refinedev/core@latest,@refinedev/simple-rest@latest,@refinedev/react-router@latest,react-router@^7.0.2
Content: import { Refine } from "@refinedev/core"; import routerProvider from "@refinedev/react-router"; import dataProvider from "@refinedev/simple-rest"; export function RefineContext({ children }) { return ( <Refine routerProvider={routerProvider} dataProvider={dataProvider("https://api.fake-rest.refine.dev")} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > {children} </Refine> ); }
Content: import { BrowserRouter, Route, Routes, Outlet } from "react-router"; import { ErrorComponent } from "@refinedev/core"; import { NavigateToResource } from "@refinedev/react-router"; import { Home } from "./pages/home.tsx"; import { About } from "./pages/about.tsx"; import { ProductList } from "./refine/pages/products/list.tsx"; import { RefineContext } from "./refine/refine-context.tsx"; export default function App() { return ( <BrowserRouter> <Routes> {/* Your existing routes */} <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> {/* Refine routes */} <Route path="/refine" element={ <RefineContext> <Outlet /> </RefineContext> } > <Route index element={<NavigateToResource />} /> <Route path="products" element={<ProductList />} /> <Route path="*" element={<ErrorComponent />} /> </Route> </Routes> </BrowserRouter> ); }
Content: import { useList } from "@refinedev/core"; export const ProductList = () => { const { data: products } = useList(); return ( <div> <h1>Refine Products Page</h1> <ul> {products?.data?.map((record) => ( <li key={record.id}>{record.name}</li> ))} </ul> </div> ); };
Content: export const Home = () => { return ( <> <h1>Home Page</h1> <p>This file represents your existing page.</p> <p>This component isn't wrapped with Refine context.</p> <a href="/about">Go to About page</a> <br /> <a href="/refine">Go to Refine page</a> </> ); };
Content: export const About = () => { return ( <div> <h1>About Page</h1> <a href="/">Go to Home page</a> </div> ); };
Next.js App
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
yarn add @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
- We start by creating
app/refine/layout.tsx
file, this layout will be used by all pages under/refine
folder. - Then we create
app/refine/products/page.tsx
file, here we can use Refine features, since it's layout is wrapped withRefine
component.
Code Example
Dependencies:
Content: "use client"; import { Refine } from "@refinedev/core"; import routerProvider from "@refinedev/nextjs-router"; import dataProvider from "@refinedev/simple-rest"; export default function RefineLayout({ children }: { children: React.ReactNode }) { return ( <Refine routerProvider={routerProvider} dataProvider={dataProvider("https://api.fake-rest.refine.dev")} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > {children} </Refine> ); }
Content: "use client"; import { useList } from "@refinedev/core"; export default function Products() { const { data: products } = useList(); return ( <div> <h1>Refine Products Page</h1> <ul> {products?.data?.map((record) => ( <li key={record.id}>{record.name}</li> ))} </ul> </div> ); }
Content: export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> ); }
Content: import Link from "next/link"; export default function Home() { return ( <main> <h1>Home Page</h1> <Link href="/about">Go to About page</Link> <br /> <Link href="/refine/products">Go to Refine page</Link> </main> ); }
Content: import Link from "next/link"; export default function AboutPage() { return ( <div> <h1>About Page</h1> <Link href="/">Go to Home page</Link> </div> ); }
Next.js Pages
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
yarn add @refinedev/core @refinedev/nextjs-router @refinedev/simple-rest
- We start by creating
src/components/layout.tsx
file, this component will be conditionally rendered bypages/_app.tsx
file. - Then we create
pages/_app.tsx
file, here we are checking if the current file hasgetLayout
function, if it does, we are rendering it by wrapping it withgetLayout
function. - Then we create
pages/refine/products.tsx
file, here we are addingPage.getLayout
to our component, so it will be wrapped withRefine
context. Then we can use Refine features, since it's layout is wrapped withRefine
component.
Code Example
Dependencies:
Content: import { Refine } from "@refinedev/core"; import routerProvider from "@refinedev/nextjs-router/pages"; import dataProvider from "@refinedev/simple-rest"; export default function RefineLayout({ children }) { return ( <Refine routerProvider={routerProvider} dataProvider={dataProvider("https://api.fake-rest.refine.dev")} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > {children} </Refine> </AntdApp> </ConfigProvider> ); }
Content: import type { ReactElement, ReactNode } from "react"; import type { NextPage } from "next"; import type { AppProps } from "next/app"; export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & { getLayout?: (page: ReactElement) => ReactNode; }; type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout; }; export default function MyApp({ Component, pageProps }: AppPropsWithLayout) { // Use the layout defined at the page level, if available const getLayout = Component.getLayout ?? ((page) => page); return getLayout(<Component {...pageProps} />); }
Content: import type { ReactElement } from "react"; import { useList } from "@refinedev/core"; import RefineLayout from "../../src/components/refine-layout"; import type { NextPageWithLayout } from "../_app"; const Page: NextPageWithLayout = () => { const { data: products } = useList(); return ( <div> <h1>Refine Products Page</h1> <ul> {products?.data?.map((record) => ( <li key={record.id}>{record.name}</li> ))} </ul> </div> ); }; Page.getLayout = function getLayout(page: ReactElement) { return <RefineLayout>{page}</RefineLayout>; }; export default Page;
Content: import Link from "next/link"; export default function AboutPage() { return ( <div> <h1>About Page</h1> <Link href="/">Go to Home page</Link> </div> ); }
Content: import Link from "next/link"; export default function Home() { return ( <> <h1>Home Page</h1> <Link href="/about">Go to About page</Link> <br /> <Link href="/refine/products">Go to Refine page</Link> </> ); }
Adding UI to Router Examples
In the following examples below, as a follow-up from the previous router examples, we will add Ant Design layout from @refinedev/antd
package.
See the UI Libraries guide for more information.
- Vite
- Next.js App
- Next.js Pages
Vite
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/react-router-v6 @refinedev/antd @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/react-router-v6 @refinedev/antd @refinedev/simple-rest
yarn add @refinedev/core @refinedev/react-router-v6 @refinedev/antd @refinedev/simple-rest
We start by modifying
refine-context.tsx
file, adding necessary imports from@refinedev/antd
package.And then in
App.tsx
file, we are updating ourErrorComponent
import from@refinedev/core
to@refinedev/antd
.Finally, in
refine/pages/products/list.tsx
file, we are importingList
component anduseTable
hook from@refinedev/antd
package.
Code Example
Dependencies: @refinedev/antd@latest,@refinedev/core@latest,@refinedev/simple-rest@latest,@refinedev/react-router@latest,react-router@^7.0.2,antd@^5.0.5
Content: import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import routerProvider from "@refinedev/react-router"; import { RefineThemes, ThemedLayoutV2 } from "@refinedev/antd"; import { App as AntdApp, ConfigProvider } from "antd"; import "@refinedev/antd/dist/reset.css"; export function RefineContext({ children }) { return ( <ConfigProvider theme={RefineThemes.Blue}> <AntdApp> <Refine routerProvider={routerProvider} dataProvider={dataProvider("https://api.fake-rest.refine.dev")} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > <ThemedLayoutV2>{children}</ThemedLayoutV2> </Refine> </AntdApp> </ConfigProvider> ); }
Content: import { BrowserRouter, Route, Routes, Outlet } from "react-router"; import { ErrorComponent } from "@refinedev/antd"; import { NavigateToResource } from "@refinedev/react-router"; import { Home } from "./pages/home.tsx"; import { About } from "./pages/about.tsx"; import { ProductList } from "./refine/pages/products/list.tsx"; import { RefineContext } from "./refine/refine-context.tsx"; export default function App() { return ( <BrowserRouter> <Routes> {/* Your existing routes */} <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> {/* Refine routes */} <Route path="/refine" element={ <RefineContext> <Outlet /> </RefineContext> } > <Route index element={<NavigateToResource />} /> <Route path="products" element={<ProductList />} /> <Route path="*" element={<ErrorComponent />} /> </Route> </Routes> </BrowserRouter> ); }
Content: import { List, useTable } from "@refinedev/antd"; import { Table } from "antd"; export const ProductList = () => { const { tableProps } = useTable(); return ( <List> <Table {...tableProps} rowKey="id"> <Table.Column dataIndex="id" title="Id" /> <Table.Column dataIndex="name" title="Name" /> <Table.Column dataIndex="price" title="Price" /> </Table> </List> ); };
Content: export const Home = () => { return ( <> <h1>Home Page</h1> <p>This file represents your existing page.</p> <p>This component isn't wrapped with Refine context.</p> <a href="/about">Go to About page</a> <br /> <a href="/refine">Go to Refine page</a> </> ); };
Content: export const About = () => { return ( <div> <h1>About Page</h1> <a href="/">Go to Home page</a> </div> ); };
Next.js App
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
yarn add @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
- We start by modifying
app/refine/layout.tsx
file, adding necessary imports from@refinedev/antd
package. - Then we modify
app/refine/products/page.tsx
file, here we are usingList
component anduseTable
hook from@refinedev/antd
package.
Code Example
Dependencies: @refinedev/antd@latest,antd@^5.0.5
Content: "use client"; import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import routerProvider from "@refinedev/nextjs-router"; import { RefineThemes, ThemedLayoutV2 } from "@refinedev/antd"; import { App as AntdApp, ConfigProvider } from "antd"; import "@refinedev/antd/dist/reset.css"; export default function RefineLayout({ children }: { children: React.ReactNode }) { return ( <ConfigProvider theme={RefineThemes.Blue}> <AntdApp> <Refine dataProvider={dataProvider("https://api.fake-rest.refine.dev")} routerProvider={routerProvider} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > <ThemedLayoutV2>{children}</ThemedLayoutV2> </Refine> </AntdApp> </ConfigProvider> ); }
Content: "use client"; import { List, useTable } from "@refinedev/antd"; import { Table } from "antd"; export default function Products() { const { tableProps } = useTable(); return ( <List> <Table {...tableProps} rowKey="id"> <Table.Column dataIndex="id" title="Id" /> <Table.Column dataIndex="name" title="Name" /> <Table.Column dataIndex="price" title="Price" /> </Table> </List> ); }
Content: export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> ); }
Content: import Link from "next/link"; export default function Home() { return ( <main> <h1>Home Page</h1> <Link href="/about">Go to About page</Link> <br /> <Link href="/refine/products">Go to Refine page</Link> </main> ); }
Content: import Link from "next/link"; export default function AboutPage() { return ( <div> <h1>About Page</h1> <Link href="/">Go to Home page</Link> </div> ); }
Next.js Pages
First, we need to install necessary packages:
- npm
- pnpm
- yarn
npm i @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
pnpm add @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
yarn add @refinedev/core @refinedev/nextjs-router @refinedev/antd @refinedev/simple-rest
- We start by updating
src/components/layout.tsx
file, adding necessary imports from@refinedev/antd
package. - Then we modify
pages/refine/products.tsx
file, here we are usingList
component anduseTable
hook from@refinedev/antd
package.
Code Example
Dependencies: @refinedev/antd@latest,antd@^5.0.5
Content: import { Refine } from "@refinedev/core"; import dataProvider from "@refinedev/simple-rest"; import routerProvider from "@refinedev/nextjs-router/pages"; import { RefineThemes, ThemedLayoutV2 } from "@refinedev/antd"; import { App as AntdApp, ConfigProvider } from "antd"; import "@refinedev/antd/dist/reset.css"; export default function RefineLayout({ children }) { return ( <ConfigProvider theme={RefineThemes.Blue}> <AntdApp> <Refine dataProvider={dataProvider("https://api.fake-rest.refine.dev")} routerProvider={routerProvider} resources={[ { name: "products", list: "/refine/products", }, ]} options={{ syncWithLocation: true }} > <ThemedLayoutV2>{children}</ThemedLayoutV2> </Refine> </AntdApp> </ConfigProvider> ); }
Content: import type { ReactElement, ReactNode } from "react"; import type { NextPage } from "next"; import type { AppProps } from "next/app"; export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & { getLayout?: (page: ReactElement) => ReactNode; }; type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout; }; export default function MyApp({ Component, pageProps }: AppPropsWithLayout) { // Use the layout defined at the page level, if available const getLayout = Component.getLayout ?? ((page) => page); return getLayout(<Component {...pageProps} />); }
Content: import type { ReactElement } from "react"; import { List, useTable } from "@refinedev/antd"; import { Table } from "antd"; import RefineLayout from "../../src/components/refine-layout"; import type { NextPageWithLayout } from "../_app"; const Page: NextPageWithLayout = () => { const { tableProps } = useTable(); return ( <List> <Table {...tableProps} rowKey="id"> <Table.Column dataIndex="id" title="Id" /> <Table.Column dataIndex="name" title="Name" /> <Table.Column dataIndex="price" title="Price" /> </Table> </List> ); }; Page.getLayout = function getLayout(page: ReactElement) { return <RefineLayout>{page}</RefineLayout>; }; export default Page;
Content: import Link from "next/link"; export default function AboutPage() { return ( <div> <h1>About Page</h1> <Link href="/">Go to Home page</Link> </div> ); }
Content: import Link from "next/link"; export default function Home() { return ( <> <h1>Home Page</h1> <Link href="/about">Go to About page</Link> <br /> <Link href="/refine/products">Go to Refine page</Link> </> ); }
Content: /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, transpilePackages: [ "@ant-design/icons-svg", "@refinedev/nextjs-router", "@refinedev/antd", "antd", "@ant-design/pro-components", "@ant-design/pro-layout", "@ant-design/pro-utils", "@ant-design/pro-provider", "rc-pagination", "rc-picker", "rc-util", ], }; module.exports = nextConfig;
Authentication
If want to use Refine with your existing application, probably you already have authentication in-place. In this case, in order to enable Authentication features of Refine
, only thing you need to do is to implement AuthProvider
's check method.
If you want to handle Authentication with Refine from scratch, check the Authentication Guide
check Method
Once you provide the check
method, you can use Authenticated component and/or useIsAuthenticated hook in your application. Refine will redirect user to given login page for unauthenticated users.
import { AuthProvider } from "@refinedev/core";
export const authProvider: AuthProvider = {
check: async () => {
const isAuthenticated = myCheckLogic();
if (isAuthenticated) {
return { authenticated: true };
}
return {
authenticated: false,
redirectTo: "/my-login-page",
error: {
name: "Authentication Failed.",
message: "User not found.",
},
};
},
login: async () => {
throw new Error("Method not implemented.");
},
logout: async () => {
throw new Error("Method not implemented.");
},
onError: async () => {
throw new Error("Method not implemented.");
},
};
Optional Methods
Following methods are optional, but could be useful for various use-cases.
getIdentity Method
getIdentity method can be used to enable useGetIdentity hook.
This hook is also used to rendering current user information in the header of UI Integration layouts.
onError
logout
logout method can be used to enable useLogout hook
This hook is also used to render Logout
button in the sider of UI Integration layouts.