Skip to main content
This quick start guide will help you build your first Refine application. We’ll create a product management app with list, create, and edit functionality.
This tutorial uses Vite + Material UI + REST API. You can choose different options based on your preferences.

Create your project

Start by creating a new Refine project using the CLI:
npm create refine-app@latest my-refine-app
When prompted, select the following options:
1

Choose Vite as your platform

Vite provides fast build times and great developer experience.
2

Select Material UI for the UI framework

Material UI offers a comprehensive set of pre-built components.
3

Pick REST API as your data provider

We’ll use a demo REST API for this tutorial.
4

Configure authentication

You can skip authentication for now or add it later.

Understanding the Refine component

The heart of every Refine application is the <Refine> component. Open src/App.tsx to see the basic structure:
src/App.tsx
import { Refine } from "@refinedev/core";
import { ThemedLayout } from "@refinedev/mui";
import dataProvider from "@refinedev/simple-rest";
import routerProvider from "@refinedev/react-router";
import { BrowserRouter, Outlet, Route, Routes } from "react-router";
import CssBaseline from "@mui/material/CssBaseline";

export default function App() {
  return (
    <BrowserRouter>
      <CssBaseline />
      <Refine
        dataProvider={dataProvider("https://api.fake-rest.refine.dev")}
        routerProvider={routerProvider}
        resources={[
          {
            name: "products",
            list: "/products",
          },
        ]}
      >
        <Routes>
          <Route
            element={
              <ThemedLayout>
                <Outlet />
              </ThemedLayout>
            }
          >
            <Route path="/products">
              <Route index element={<ProductList />} />
            </Route>
          </Route>
        </Routes>
      </Refine>
    </BrowserRouter>
  );
}
The dataProvider prop tells Refine how to communicate with your backend API. The resources prop defines the data entities in your application.

Create a list page

Now let’s create a page to display a list of products. Create a new file src/pages/products/list.tsx:
src/pages/products/list.tsx
import React from "react";
import { List, useDataGrid, DateField } from "@refinedev/mui";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { useMany } from "@refinedev/core";

export const ProductList = () => {
  const { dataGridProps } = useDataGrid();

  const { data: categories, isLoading } = useMany({
    resource: "categories",
    ids:
      dataGridProps?.rows?.map((item) => item?.category?.id).filter(Boolean) ??
      [],
    queryOptions: {
      enabled: !!dataGridProps?.rows,
    },
  });

  const columns = React.useMemo<GridColDef[]>(
    () => [
      { field: "id", headerName: "ID", type: "number" },
      { field: "name", flex: 1, headerName: "Name" },
      {
        field: "category",
        flex: 1,
        headerName: "Category",
        display: "flex",
        renderCell: ({ value }) =>
          isLoading
            ? "Loading..."
            : categories?.data?.find((item) => item.id === value?.id)?.title,
      },
      {
        field: "createdAt",
        flex: 1,
        headerName: "Created at",
        display: "flex",
        renderCell: ({ value }) => <DateField value={value} />,
      },
    ],
    [categories?.data, isLoading],
  );

  return (
    <List>
      <DataGrid {...dataGridProps} columns={columns} />
    </List>
  );
};

What’s happening here?

Let’s break down the key parts:
  • useDataGrid hook - Automatically handles pagination, sorting, and filtering for Material UI’s DataGrid
  • useMany hook - Fetches related category data for each product
  • <List> component - Provides a pre-built wrapper with create button, breadcrumbs, and other utilities
  • <DataGrid> component - Material UI’s data table with built-in features
Refine hooks like useDataGrid and useMany automatically communicate with your data provider, managing loading states, error handling, and caching.

Add create and edit pages

Update your resources configuration to include create and edit routes:
src/App.tsx
resources={[
  {
    name: "products",
    list: "/products",
    create: "/products/create",
    edit: "/products/edit/:id",
  },
]}
Refine will automatically:
  • Add a “Create” button to the list page
  • Add “Edit” buttons to each row in the table
  • Handle navigation between pages

Run your application

Start the development server:
npm run dev
Open your browser at http://localhost:5173 and you’ll see your Refine application with:
  • A navigation menu automatically generated from your resources
  • A product list page with sorting and pagination
  • Loading states and error handling built-in

Key concepts you’ve learned

1

The Refine component

The <Refine> component is the entry point that configures your application with providers and resources.
2

Data providers

Data providers abstract away API communication, making it easy to switch between different backends.
3

Resources

Resources define your data entities and their routes. Refine uses this to generate navigation and route handling.
4

Hooks

Refine hooks like useDataGrid and useMany handle data fetching, mutations, and state management automatically.

Next steps

Now that you have a basic Refine application running, you can:

Add authentication

Secure your application with login and access control

Customize the UI

Style your application and override default components

Connect to your API

Replace the demo API with your own backend

Follow the tutorial

Build a full-featured CRUD application step-by-step
Explore real-world examples to see how Refine handles complex scenarios like multi-tenancy, real-time updates, and advanced filtering.

Build docs developers (and LLMs) love