Building Data-Driven Apps with React Admin
If you’ve ever built an admin dashboard from scratch—wiring up tables, forms, pagination, and API calls by hand—you know how much boilerplate it takes before you write a single line of business logic. React Admin cuts through that by giving you a structured framework for building CRUD apps on top of any API. This article walks through how it works, focusing on the architecture that makes it backend-agnostic and genuinely reusable.
Key Takeaways
- React Admin is a React framework for building data-driven admin dashboards, not a UI template. It separates your data layer from your UI layer through a
dataProviderabstraction. - The
dataProvideris built around nine core methods that adapt React Admin to any backend—REST, GraphQL, Supabase, or otherwise—making the framework truly backend-agnostic. - List and edit views are declarative: you compose field components and input components, and React Admin handles data fetching, pagination, sorting, and relationship resolution automatically.
- Authentication, role-based access control, and real-time updates are handled through separate providers and optional extensions, keeping the core framework focused and modular.
What React Admin Actually Is
React Admin isn’t a UI template. It’s a React framework purpose-built for data-driven admin dashboards and internal tools. It ships with components for listing, creating, editing, and deleting records, but the real value is in how it separates your data layer from your UI layer.
At its core, React Admin v5 is built on React Query, react-hook-form, and react-router. It defaults to MUI, but it’s not limited to it—React Admin supports headless usage, meaning you can bring your own component library if needed.
The Three Building Blocks: Admin, Resource, and dataProvider
Every React Admin app starts with three concepts:
<Admin>— the root component that wires everything together<Resource>— maps a name to a set of CRUD views and an API endpointdataProvider— the adapter between React Admin and your backend
import { Admin, Resource } from "react-admin"
import { dataProvider } from "./dataProvider"
import { MovieList } from "./MovieList"
import { MovieEdit } from "./MovieEdit"
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="movies" list={MovieList} edit={MovieEdit} />
</Admin>
)
When a user navigates to the movies list, React Admin calls dataProvider.getList("movies", params). When they edit a record, it calls dataProvider.update("movies", params). The UI never talks to your API directly.
How the React Admin dataProvider Works
The dataProvider is built around nine core methods: getList, getOne, getMany, getManyReference, create, update, updateMany, delete, and deleteMany. Each method receives a request object and returns a Promise, and providers can be extended with additional methods when needed.
const dataProvider = {
getList: async (resource, params) => {
const { page, perPage } = params.pagination
const { field, order } = params.sort
const url = `${apiUrl}/${resource}?page=${page}&perPage=${perPage}&sort=${field}&order=${order}`
const { json, headers } = await httpClient(url, { signal: params.signal })
return {
data: json,
total: parseInt(headers.get("content-range").split("/").pop(), 10),
}
},
// ...other methods
}
React Admin doesn’t care whether your backend is REST, GraphQL, Supabase, or even IndexedDB. As long as every record has a consistent id field and your dataProvider returns the expected shape, it works. Pre-built adapters exist for common backends—ra-data-simple-rest, ra-data-graphql, and others—so you often don’t need to write one from scratch.
Handling Authentication
Authentication isn’t baked into the dataProvider. React Admin uses a separate authProvider for login, logout, and permission checks. A common pattern is to store a token after login and read it inside your dataProvider when making requests, but React Admin also supports integration with external identity providers.
const httpClient = (url, options = {}) => {
options.user = {
authenticated: true,
token: localStorage.getItem("token"),
}
return fetchUtils.fetchJson(url, options)
}
Discover how at OpenReplay.com.
Building List and Edit Views
Once your dataProvider is wired up, building views is mostly declarative. For list views, React Admin’s <Datagrid> component renders columns based on field components you compose. Note that <Datagrid> is still widely used, but newer versions also introduce <DataTable> as a more modern alternative.
import { List, Datagrid, TextField, DateField, ReferenceField } from "react-admin"
export const MovieList = () => (
<List>
<Datagrid rowClick="edit">
<TextField source="title" />
<DateField source="release" />
<ReferenceField source="director_id" reference="directors">
<TextField source="lastname" />
</ReferenceField>
</Datagrid>
</List>
)
<ReferenceField> automatically calls dataProvider.getMany("directors", ...) to resolve related records—no manual fetching required.
Edit forms follow the same pattern using <Edit> and <SimpleForm>:
import { Edit, SimpleForm, TextInput, DateInput } from "react-admin"
export const MovieEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="title" />
<DateInput source="release" />
</SimpleForm>
</Edit>
)
When You Need Custom Logic
For resource-specific behavior—like deleting related records before a parent is removed—React Admin provides withLifecycleCallbacks:
import { withLifecycleCallbacks } from "react-admin"
export const dataProvider = withLifecycleCallbacks(baseDataProvider, [
{
resource: "movies",
beforeDelete: async (params, dp) => {
const { data: reviews } = await dp.getList("reviews", {
filter: { movie_id: params.id },
pagination: { page: 1, perPage: 1000 },
sort: { field: "id", order: "DESC" },
})
await dp.deleteMany("reviews", { ids: reviews.map((r) => r.id) })
return params
},
},
])
This keeps your business logic close to the data layer without scattering it across components.
What React Admin Doesn’t Do Out of the Box
A few things worth knowing before you commit:
- RBAC (fine-grained role-based access control) requires the enterprise module; basic permission checks are handled through the
authProvider - Real-time updates require a compatible realtime data provider and additional setup
- File uploads need custom dataProvider logic to handle
multipart/form-data
React Admin is also compatible with frameworks like Next.js (including both Pages and App Router) and supports alternative routing solutions beyond its default setup.
Conclusion
React Admin’s strength is its dataProvider abstraction. Once you implement those core methods against your API, you get a fully functional CRUD admin dashboard with sorting, filtering, pagination, and relationship handling—without building any of it yourself. Start with a pre-built adapter if one fits your backend, write a custom one if not, and layer in authentication and lifecycle callbacks as your app grows.
FAQs
Yes. React Admin is backend-agnostic by design. You can use the official ra-data-graphql adapter or write a custom dataProvider that maps the required methods to your GraphQL queries and mutations. As long as each record includes a consistent id field and your provider returns the expected response shape, React Admin works the same regardless of the backend.
React Admin provides reference components like ReferenceField and ReferenceInput that automatically fetch related records through your dataProvider. For example, ReferenceField calls dataProvider.getMany to resolve foreign keys into display values. You declare the relationship in your component tree, and React Admin handles the data fetching and caching behind the scenes.
The open-source version supports basic authentication and simple permission checks through the authProvider. For granular role-based access control, such as hiding fields or restricting actions per role, you need the enterprise RBAC module. Evaluate your permission requirements early to decide whether the free tier meets your needs.
Yes. React Admin defaults to MUI but supports headless usage, meaning you can replace the entire UI layer with your own component library. You can also customize the MUI theme, override individual components, or build fully custom views while still using React Admin hooks for data fetching, form handling, and routing.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.