AdminJS Admin Panel Development
AdminJS — open-source Node.js framework auto-generating admin interface based on data models. Supports TypeORM, Prisma, Mongoose, Sequelize. Written in React, highly customizable.
Installation and Basic Setup
npm install adminjs @adminjs/express express express-session
npm install @adminjs/typeorm # or @adminjs/prisma, @adminjs/mongoose
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';
import { Database, Resource, getModelByName } from '@adminjs/typeorm';
AdminJS.registerAdapter({ Database, Resource });
const adminJs = new AdminJS({
resources: [
{
resource: getModelByName('User'),
options: {
properties: {
password: { isVisible: { list: false, edit: false, filter: false, show: false } },
createdAt: { isVisible: { edit: false } }
},
actions: {
delete: { isAccessible: ({ currentAdmin }) => currentAdmin?.role === 'superadmin' }
}
}
},
{
resource: getModelByName('Order'),
options: {
listProperties: ['id', 'customer', 'status', 'total', 'createdAt'],
filterProperties: ['status', 'createdAt'],
sort: { sortBy: 'createdAt', direction: 'desc' }
}
}
],
dashboard: {
component: AdminJS.bundle('./components/Dashboard')
},
branding: {
companyName: 'My Store',
logo: '/admin-logo.svg'
}
});
const router = AdminJSExpress.buildAuthenticatedRouter(adminJs, {
authenticate: async (email, password) => {
const admin = await Admin.findOne({ email });
if (admin && await bcrypt.compare(password, admin.passwordHash)) {
return admin;
}
return null;
},
cookiePassword: process.env.COOKIE_SECRET
});
Custom Components
AdminJS allows replacing standard components with custom React:
// components/OrderStatusCell.tsx
import { BasePropertyProps } from 'adminjs';
const OrderStatusCell: React.FC<BasePropertyProps> = ({ record }) => {
const status = record.params.status;
const colors = { pending: 'orange', completed: 'green', cancelled: 'red' };
return <span style={{ color: colors[status] }}>{status}</span>;
};
export default OrderStatusCell;
// In resource config
properties: {
status: {
components: { list: AdminJS.bundle('./components/OrderStatusCell') }
}
}
Custom Actions
actions: {
sendNotification: {
actionType: 'record',
icon: 'Bell',
label: 'Notify customer',
handler: async (request, response, context) => {
const { record } = context;
await NotificationService.send(record.params.customerId, 'order_ready');
return {
record: record.toJSON(),
notice: { message: 'Notification sent', type: 'success' }
};
}
}
}
File Upload via @adminjs/upload
npm install @adminjs/upload
import uploadFeature from '@adminjs/upload';
import { s3Client } from './s3-client';
{
resource: getModelByName('Product'),
features: [
uploadFeature({
provider: { aws: { bucket: 'my-bucket', s3Client } },
properties: {
file: 'imageFile',
filePath: 'imageUrl',
filename: 'imageName',
mimeType: 'imageMimeType'
},
uploadPath: (record, filename) => `products/${record.id()}/${filename}`
})
]
}
Roles and Permissions
const canModifyOrders = ({ currentAdmin }: { currentAdmin: Admin }) =>
['superadmin', 'manager'].includes(currentAdmin?.role);
{
resource: getModelByName('Order'),
options: {
actions: {
edit: { isAccessible: canModifyOrders },
delete: { isAccessible: ({ currentAdmin }) => currentAdmin?.role === 'superadmin' }
}
}
}
AdminJS Limitations
- Complex custom workflows require lots of code — loses benefit over custom panel
- Performance on large volumes (100k+ records) requires manual query optimization
- Limited mobile display options
Development timeline: 2–3 weeks for panel with custom components, file uploads, and configured permissions.







