Docs / Programming & Development / Deploy Refine Admin Panel

Deploy Refine Admin Panel

By Admin · Mar 15, 2026 · Updated Apr 24, 2026 · 188 views · 4 min read

Refine is a React framework for building data-intensive admin panels and internal tools. It provides hooks and components for CRUD operations, authentication, access control, and real-time updates — working with any REST, GraphQL, or custom API backend. This guide covers building and deploying a Refine admin panel.

Project Setup

# Create Refine project with CLI
npm create refine-app@latest my-admin
cd my-admin

# Select during setup:
# UI Framework: Ant Design / Material UI / Mantine
# Data Provider: REST API / Hasura / Supabase / Strapi
# Auth Provider: Custom / Auth0 / Supabase

Data Provider Configuration

// src/App.tsx
import { Refine } from "@refinedev/core";
import { ThemedLayoutV2 } from "@refinedev/antd";
import dataProvider from "@refinedev/simple-rest";
import routerProvider from "@refinedev/react-router-v6";
import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Refine
        dataProvider={dataProvider("https://api.example.com")}
        routerProvider={routerProvider}
        resources={[
          {
            name: "users",
            list: "/users",
            create: "/users/create",
            edit: "/users/edit/:id",
            show: "/users/show/:id",
          },
          {
            name: "posts",
            list: "/posts",
            create: "/posts/create",
            edit: "/posts/edit/:id",
          },
        ]}
      >
        <Routes>
          <Route element={<ThemedLayoutV2><Outlet /></ThemedLayoutV2>}>
            <Route path="/users" element={<UserList />} />
            <Route path="/users/create" element={<UserCreate />} />
            <Route path="/users/edit/:id" element={<UserEdit />} />
          </Route>
        </Routes>
      </Refine>
    </BrowserRouter>
  );
}

CRUD Pages

// src/pages/users/list.tsx
import { List, useTable, EditButton, ShowButton, DeleteButton } from "@refinedev/antd";
import { Table, Space } from "antd";

export const UserList = () => {
  const { tableProps } = useTable({
    sorters: { initial: [{ field: "id", order: "desc" }] },
    filters: { initial: [{ field: "role", operator: "eq", value: "admin" }] },
  });

  return (
    <List>
      <Table {...tableProps} rowKey="id">
        <Table.Column dataIndex="id" title="ID" sorter />
        <Table.Column dataIndex="name" title="Name" sorter />
        <Table.Column dataIndex="email" title="Email" />
        <Table.Column dataIndex="role" title="Role" />
        <Table.Column title="Actions" render={(_, record) => (
          <Space>
            <EditButton recordItemId={record.id} size="small" />
            <ShowButton recordItemId={record.id} size="small" />
            <DeleteButton recordItemId={record.id} size="small" />
          </Space>
        )} />
      </Table>
    </List>
  );
};

Building and Deploying

# Build static files
npm run build
# Output in dist/ or build/

# Deploy as static site behind Nginx
server {
    listen 443 ssl http2;
    server_name admin.example.com;

    ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;

    root /opt/admin-panel/dist;
    index index.html;

    # SPA routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Docker Deployment

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

Authentication

// src/providers/auth.ts
import { AuthProvider } from "@refinedev/core";

export const authProvider: AuthProvider = {
  login: async ({ email, password }) => {
    const response = await fetch("https://api.example.com/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, password }),
    });
    if (response.ok) {
      const { token } = await response.json();
      localStorage.setItem("token", token);
      return { success: true, redirectTo: "/" };
    }
    return { success: false, error: { message: "Invalid credentials" } };
  },
  logout: async () => {
    localStorage.removeItem("token");
    return { success: true, redirectTo: "/login" };
  },
  check: async () => {
    const token = localStorage.getItem("token");
    return { authenticated: Boolean(token) };
  },
  getIdentity: async () => {
    const token = localStorage.getItem("token");
    if (!token) return null;
    const response = await fetch("https://api.example.com/auth/me", {
      headers: { Authorization: "Bearer " + token },
    });
    return response.json();
  },
};

Summary

Refine accelerates admin panel development by providing pre-built hooks and components for CRUD operations, filtering, sorting, pagination, and authentication. It works with any backend API through data providers, making it easy to build dashboards for existing services. Since Refine outputs a static React application, deployment is simple — serve the built files from Nginx or any static hosting. For internal tools and admin interfaces, Refine eliminates weeks of repetitive UI development.

Was this article helpful?