Skip to main content
Version: 3.xx.xx


What is refine?

refine is a React-based framework for rapid building of internal tools. It's is a a collection of helper hooks, components and providers. They are all decoupled from your UI components and business logic, so they never keep you from customizing your UI or coding your own flow.

Refine offers lots of out-of-the box functionality for rapid development, without compromising extreme customizability. Use-cases include, but are not limited to admin panels, B2B applications and dashboards.

Key features

🔥 Headless : Works with any UI framework

⚙️ Zero-configuration : One-line setup with superplate. It takes less than a minute to start a project.

📦 Out-of-the-box : Routing, networking, authentication, state management, i18n and UI.

🔌 Backend Agnostic : Connects to any custom backend. Built-in support for REST API, GraphQL, NestJs CRUD, Airtable, Strapi, Strapi v4, Strapi GraphQL, Supabase, Hasura, Nhost, Appwrite, Firebase, Directus and Altogic.

📝 Native Typescript Core : You can always opt out for plain JavaScript.

🐜 Enterprise UI : Works seamlessly with Ant Design System, and Material UI. (Support for other UI frameworks is on the Roadmap)

📝 Boilerplate-free Code : Keeps your codebase clean and readable.


Higher-level frontend frameworks can save you a lot time, but they typically offer you a trade-off between speed and flexibility.

After many years of experience in developing B2B frontend applications and working with popular frameworks, we came up with a new approach to tackle this dilemma. This is how refine is born.

As refine is totally unopinionated about UI and logic, it's strongly opinionated about three parts of your application:

  1. API Networking
  2. State Management
  3. Authentication & Authorization

We believe, these are the most important components of a data-intensive frontend application and should be handled in a robust way by leveraging industry best practices.

refine guarantees you a perfect implementation of these building blocks in your project, so you can focus on your development.


refine makes extensive use of hooks as a default way for interacting with your components. Under the hood, refine relies heavily to React Query for data handling, caching and state management. Access to external sources and API's happen via providers which are basically plug-in type components for extendibility.


After releasing the first internal versions, we had the chance to migrate some of our React projects to refine. In addition to shorter development times and overall performance gains, we've measured significant reduction in project size.

refine makes your codebase significantly smaller, by eliminating redundant code such as reducers, actions and unit tests. Below is a size comparison for an example project:

Quick Start

Run the superplate tool with the following command:

npx superplate-cli -p refine-react tutorial

Follow the CLI wizard to select options and start creating your project.

Select the following options to complete the _CLI wizard_:

CLI options selection
? What will be the name of your app:
> tutorial

? Do you want to use a UI Framework?:
❯ Ant Design

? Do you want a customized theme?:
❯ Default theme

? Router Provider:
❯ React Router v6

? Data Provider:

? Auth Provider:
❯ None

? Do you want to add example pages?:
❯ No

? Do you want a customized layout?:
❯ No

? Do you want to add Kbar command pallete?:
❯ No

? i18n - Internationalization:
❯ No

After setup is complete, navigate to the project folder and start your project with:

npm run dev

Your refine application will be accessible at http://localhost:3000.

Replace the contents of App.tsx with the following code:

import { Refine, useMany } from "@pankod/refine-core";
import { useTable, List, Table, DateField } from "@pankod/refine-antd";
import routerProvider from "@pankod/refine-react-router-v6";
import dataProvider from "@pankod/refine-simple-rest";

import "@pankod/refine-antd/dist/styles.min.css";

const App: React.FC = () => {
return (
resources={[{ name: "posts", list: PostList }]}

export const PostList: React.FC = () => {
const { tableProps } = useTable<IPost>();

const categoryIds =
tableProps?.dataSource?.map((item) => ?? [];

const { data, isLoading } = useMany<ICategory>({
resource: "categories",
ids: categoryIds,
queryOptions: {
enabled: categoryIds.length > 0,

return (
<Table<IPost> {...tableProps} rowKey="id">
<Table.Column dataIndex="title" title="title" />
dataIndex={["category", "id"]}
render={(value: number) => {
if (isLoading) {
return "loading...";

return data?.data.find(
(item: ICategory) => === value,
render={(value: string) => (
<DateField format="LLL" value={value} />

export default App;
interface IPost {
title: string;
createdAt: string;
category: { id: number };

interface ICategory {
id: number;
title: string;

Next Steps