Note: when the standard admin panel is too rigid, and custom development is too expensive, AdminJS (see GitHub repository) offers a golden mean. But out of the box, it often doesn't cover complex business rules: custom actions, file uploads, role-based access. We have developed admin panels on AdminJS for e-commerce, logistics, and SaaS with over 20 projects under our belt. Once, for a retail chain, we implemented a custom action for bulk price changes — processing 5,000 products in 30 seconds. In this article, we'll share how to customize AdminJS, what tools we use, and where the boundaries of possibilities lie.
What problems does AdminJS solve?
AdminJS generates a CRUD interface based on data models. It is suitable for quickly launching an admin panel but requires refinement for non-standard scenarios. Here are the main challenges we address:
- Custom actions — bulk mailing, report generation, integration with external APIs. For example, for a logistics startup, we added an action to automatically create waybills, processing 10,000 records per minute.
- File uploads — via
@adminjs/uploadwith S3 or local storage. We support auto-generation of previews and thumbnails for product images. - Access rights — role-based and action-based (view, edit, delete). We configure a role model based on
currentAdmin.rolewith cascading permissions. - Custom components — replacing standard fields with React widgets: datepicker, autocomplete, WYSIWYG editors. For one client, we developed a warehouse selection component with geolocation.
- Performance — query optimization for tables with 100k+ records: adding indexes, using server-side filtering, connecting Elasticsearch for full-text search.
How to customize AdminJS for business requirements?
Stack: Node.js, TypeScript, React 18, AdminJS 7.x, TypeORM / Prisma. Deployment — Docker, Nginx, Vercel.
Consider an example: an online store with products, orders, and customers. Basic AdminJS setup with authentication and custom permissions:
AdminJS configuration code example
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 component for displaying order status with color:
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; Uploading product images to S3 via @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}` }) ] } Why does AdminJS save up to 60% time and budget?
Writing an admin panel from scratch on React and Express takes about 3–4 weeks for a typical CRUD. AdminJS reduces this to 1–2 weeks, which is 2-3 times faster. For projects with 10+ entities, time savings reach 60%, and consequently budget savings. When adding custom components, savings remain at 30–40%.
According to the official AdminJS documentation, the framework supports all popular ORMs and speeds up development by generating an interface from models. But it's important to understand: the out-of-the-box version provides basic functionality, and real savings come with proper configuration and customization.
| ORM | Development Speed | Customization Complexity |
|---|---|---|
| TypeORM | High | Low |
| Prisma | Medium | Medium |
| Mongoose | High | Low |
| Sequelize | Medium | Medium |
What to do if AdminJS performance is unsatisfactory?
For tables with 100k+ records, standard mechanisms can slow down. We apply several approaches. First, server-side filtering: all filters are executed on the database side, not on the frontend. Second, indexing frequently queried fields. Third, avoiding find with loading all related entities; we use QueryBuilder with select only. In extreme cases, we connect Elasticsearch for full-text search.
Optimization example: in one project, an order table (200k records) opened in 5 seconds. After adding a composite index on (status, createdAt) and filtering by status, the load time dropped to 200 ms.
How we develop the admin panel?
| Stage | Time (days) |
|---|---|
| Analysis | 1 |
| Design | 1-2 |
| Implementation | 5-10 |
| Testing | 2-3 |
| Deployment | 1 |
- Analysis — study data structure, business processes, access rights. Estimate scope in 1 day.
- Design — define resources, actions, components, permission scheme.
- Implementation — configure AdminJS, write custom components and actions, integrate with external services.
- Testing — scenario verification, load testing (up to 10,000 requests).
- Deployment and documentation — deploy on your server, provide instructions for administrators.
What is included in the result
- Fully functional admin panel on AdminJS with authentication.
- Custom components and actions as per your specifications.
- Integration with file uploads (S3, MinIO).
- Access rights differentiation (roles, actions).
- Source code, documentation, deployment instructions.
- 6-month warranty on identified bugs.
For simple projects, AdminJS reduces admin panel development time by 60% compared to writing from scratch. Contact us to discuss your project — get a consultation and preliminary estimate within 1 day. Order development of an admin panel on AdminJS.







