adonisjs-adminizer-provider is a package for AdonisJS 7+ that allows you to quickly add a fully-featured administrative panel to your application. Supports user and group management, media files, change history, notifications, filters, and multilingual support.
- CRUD for system and business models — automatically generated forms and lists
- User and group management — built-in role system with
manyToManyrelationships - Authentication and self-registration — login, logout, user registration with default group configuration
- Media manager — file uploads (images, videos, text documents), automatic image variant generation
- Change history — tracking all create/update/delete actions on business models
- Notifications — internal notification system with channels and read tracking
- Saved filters — named filters with conditions, sorting, and visibility for users
- Multilingual support (i18n) — support for multiple languages in the admin panel interface
- Dashboard — admin panel start page with customizable title and text
- AI Assistant — experimental AI assistant support (OpenAI, dummy)
- Customizable navigation — additional links in navbar, custom sections
- Node.js 24+
- AdonisJS ^7.0.0
- Lucid ORM ^22.0.0
- SQLite / PostgreSQL / MySQL
npm install adonisjs-adminizer-providerRun the configuration command, which automatically:
- Adds the provider to
.adonisrc.ts - Defines environment variables (
JWT_SECRET,AP_PASSWORD_SALT) - Creates migrations (11 files) for system tables
- Creates models (10 files) in
app/models/adminizer/ - Creates the configuration file
config/adminizer.ts
node ace configure adonisjs-adminizer-providernode ace migration:runAfter this, the admin panel is available at /admin.
The configuration file config/adminizer.ts consists of three main parts.
Here you register system models (generated by the package) and your application's business models:
import AdminizerUser from '#models/adminizer/adminizer_user'
import AdminizerGroup from '#models/adminizer/adminizer_group'
import AdminizerFilter from '#models/adminizer/adminizer_filter'
import AdminizerFilterColumn from '#models/adminizer/adminizer_filter_column'
import AdminizerHistoryAction from '#models/adminizer/adminizer_history_action'
import AdminizerNotification from '#models/adminizer/adminizer_notification'
import AdminizerUserNotification from '#models/adminizer/adminizer_user_notification'
import AdminizerMedia from '#models/adminizer/adminizer_media'
import AdminizerMediaMeta from '#models/adminizer/adminizer_media_meta'
import AdminizerMediaAssociation from '#models/adminizer/adminizer_media_association'
import Category from '#models/category'
import Test from '#models/test'
export default defineConfig({
models: {
// System models (do not change unless necessary)
AdminizerUser: {
Model: AdminizerUser,
overrides: {
apiKey: { columnName: 'userApiKey' },
},
},
AdminizerGroup: { Model: AdminizerGroup },
AdminizerFilter: { Model: AdminizerFilter },
AdminizerFilterColumn: { Model: AdminizerFilterColumn },
AdminizerHistoryAction: { Model: AdminizerHistoryAction },
AdminizerNotification: { Model: AdminizerNotification },
AdminizerUserNotification: {
Model: AdminizerUserNotification,
overrides: {
notificationId: {
type: 'association',
model: 'Notification',
via: 'notificationId',
sourceRelation: 'notification',
},
},
},
AdminizerMedia: { Model: AdminizerMedia },
AdminizerMediaMeta: { Model: AdminizerMediaMeta },
AdminizerMediaAssociation: { Model: AdminizerMediaAssociation },
// Your application's business models
Category: { Model: Category },
Test: { Model: Test },
},
// ...
})Each entry can include overrides to reassign column names or associations.
Maps internal adminizer model names to your Lucid models:
systemModels: {
User: 'AdminizerUser',
Group: 'AdminizerGroup',
Filter: 'AdminizerFilter',
FilterColumn: 'AdminizerFilterColumn',
HistoryActions: 'AdminizerHistoryAction',
Notification: 'AdminizerNotification',
UserNotification: 'AdminizerUserNotification',
},Detailed information here
adminpanelConfig: {
// Default model — records per page
list: {
defaultPageSize: 5
},
// ORM (always 'lucid' for this package)
system: {
defaultORM: 'lucid',
},
// Media manager
mediamanager: {
fileStoragePath: 'public',
allowMIME: ['image/*', 'application/*', 'text/*', 'video/*'],
maxByteSize: 1024 * 1024 * 2, // 2 MB
imageSizes: {
lg: { width: 750, height: 750 },
sm: { width: 350, height: 350 },
},
},
// Notifications
notifications: {
enabled: true,
enableGeneral: true,
initTab: 'general',
},
// Change history
history: {
enabled: true,
adapter: "default",
// excludeModels: ["SomeModel"] // Exclude a model from history
},
// Saved filters (experimental)
filters: {
enabled: false
},
// CORS
cors: {
enabled: false,
origin: 'http://localhost:3000',
path: 'api/*'
},
// AI Assistant (experimental)
aiAssistant: {
enabled: false,
defaultModel: 'openai-data',
models: ['openai-data', 'dummy'],
},
// Admin panel URL prefix
routePrefix: '/admin',
// Authentication
auth: {
enable: true
},
// New user registration
registration: {
enable: true,
defaultUserGroup: "guest",
confirmationRequired: false
},
// Dashboard
dashboard: true,
// Additional navbar links
navbar: {
additionalLinks: []
},
// Custom sections
sections: [],
// Dashboard welcome page
welcome: {
title: 'Demo AdonisJS adminpanel',
text: 'Demo text'
},
// Multilingual support
translation: {
locales: ['en'],
directory: 'custom-locales',
defaultLocale: 'en'
},
// Documentation link
showVersion: {
link: 'https://docs.adminizer.org',
hint: 'Adminizer documentation',
},
}To connect a simple model, simply add it to models:
// config/adminizer.ts
import Test from '#models/test'
models: {
Test: { Model: Test },
}Models with fields for file uploads (JSON type) are automatically recognized:
// database/migrations/create_categories_table.ts
schema.create('categories', (table) => {
table.increments('id')
table.string('slug').unique()
table.string('title')
table.text('description').nullable()
table.json('svgs') // Multiple SVG upload
table.json('images') // Multiple image upload
table.json('single') // Single file upload
table.timestamp('created_at')
table.timestamp('updated_at')
})// config/adminizer.ts
import Category from '#models/category'
models: {
Category: { Model: Category },
}In adminpanelConfig.models you can configure field display:
adminpanelConfig: {
models: {
Category: {
fields: {
svgs: {
groupName: 'graphics',
accept: 'image/svg+xml',
displayName: 'SVG icons',
},
images: {
groupName: 'photos',
accept: 'image/*',
displayName: 'Images',
},
single: {
displayName: 'File',
},
createdAt: {
visible: false, // Hide field from UI
},
updatedAt: {
visible: false,
},
},
// CRUD operation access control
add: true,
edit: true,
view: true,
remove: true,
},
},
}Models with Lucid associations (belongsTo, hasMany, manyToMany) are automatically displayed in the UI:
// models/test.ts
import { belongsTo, HasMany, column, BaseModel } from '@adonisjs/lucid/orm'
import Example from '#models/example'
export default class Test extends BaseModel {
@column({ isPrimary: true })
declare id: number
@column()
declare name: string
@column()
declare description: string
@column()
declare exampleId: number
@belongsTo(() => Example)
declare example: Example
}// config/adminizer.ts
models: {
Test: { Model: Test },
}Built-in login and registration system for admin panel users. Configured in adminpanelConfig:
auth: {
enable: true // Enable login
},
registration: {
enable: true, // Enable registration
defaultUserGroup: "guest", // Default group
confirmationRequired: false // Require confirmation
},After setting registration.enable: true, any visitor can register at /admin/register.
Full-featured media library:
- Support for images, videos, text files, documents
- Automatic creation of image thumbnails (
lg,sm) - MIME type filtering
- File size limits
- File attachment to model records and widgets
Configured in adminpanelConfig.mediamanager:
mediamanager: {
fileStoragePath: 'public', // Storage folder
allowMIME: ['image/*', 'application/*', 'text/*', 'video/*'],
maxByteSize: 1024 * 1024 * 2, // Max 2 MB
imageSizes: {
lg: { width: 750, height: 750 },
sm: { width: 350, height: 350 },
},
},Automatically logs all create/update/delete operations on business models:
history: {
enabled: true,
adapter: "default",
// excludeModels: ["SomeModel"] // Exclude a model from history
},Each record contains: action type, record ID, data, JSON diff between old and new versions.
Internal notification system:
- Create notifications through interface or code
- Notification channels (general, personal, etc.)
- Read tracking
- Customizable metadata
notifications: {
enabled: true,
enableGeneral: true,
initTab: 'general',
},Experimental feature — named filters for models:
- Filter conditions (JSON)
- Sort configuration
- Visibility (private / group shared)
- API key for external requests
filters: {
enabled: true // Disabled by default (experimental)
},Support for multiple languages in the admin panel interface:
translation: {
locales: ['en', 'ru'], // Available languages
directory: 'custom-locales', // Translations folder
defaultLocale: 'en', // Default language
},Translations are stored in custom-locales/ relative to the project root.
Modules can be attached to adminizer on the fly. In AdonisJS, this can be done through a provider:
import type { ApplicationService } from '@adonisjs/core/types'
import {NotificationSenderApp} from "../app/adminizer_apps/notification-sender/NotificationSenderApp.js"; // your module
export default class AdminizerAppProvider {
constructor(protected app: ApplicationService) {}
/**
* Register bindings to the container
*/
register() {}
/**
* The container bindings have booted
*/
async boot() {}
/**
* The application has been booted
*/
async start() {}
/**
* The process has been started
*/
async ready() {
const adminizer = await this.app.container.make('adminizer');
await adminizer.appManager.enable(new NotificationSenderApp());
}
/**
* Preparing to shutdown the app
*/
async shutdown() {}
}For more detailed information about modules, see the documentation
Important!
Your provider must be placed below adonisjs-adminizer-provider in adonisrc.ts:
{
file: () => import('adonisjs-adminizer-provider/provider'),
environment: ['web'],
},
{
file: () => import('#providers/adminizer_app_provider'),
environment: ['web'],
}