AdonisJS : Découvrez le Laravel de JavaScript - Le Framework Full-Stack qui Révolutionne Node.js
Découvrez AdonisJS 6, le framework Node.js TypeScript-first qui s'inspire de Laravel. Un écosystème complet avec ORM, authentification, validation, et bien plus pour créer des applications web modernes et des APIs robustes rapidement.

Si vous êtes développeur PHP et que vous appréciez Laravel pour sa simplicité et ses fonctionnalités complètes, ou si vous cherchez un framework Node.js robuste pour vos projets, laissez-moi vous présenter AdonisJS - souvent surnommé "le Laravel de JavaScript".
AdonisJS est un framework TypeScript-first pour créer des applications web et des serveurs API, qui apporte à l'écosystème Node.js la philosophie et l'élégance qu'on retrouve dans Laravel. Avec la sortie récente d'AdonisJS v6, ce framework a atteint une maturité impressionnante.
Pourquoi AdonisJS est-il Considéré comme le Laravel de JavaScript ?
1. Philosophie "Convention over Configuration"
Comme Laravel, AdonisJS privilégie les conventions sensées plutôt que la configuration excessive. Vous pouvez commencer à développer immédiatement sans passer des heures à configurer votre projet.
2. Écosystème Complet
AdonisJS fournit tout ce dont vous avez besoin :
- ORM Lucid (équivalent d'Eloquent)
- Système d'authentification intégré
- Validation de données robuste
- Gestion des emails et notifications
- CLI puissant pour la génération de code
- Tests intégrés
3. Architecture MVC Claire
Une structure familière pour les développeurs venant de Laravel ou d'autres frameworks MVC.
Les Nouveautés d'AdonisJS 6
La version 6 d'AdonisJS adopte complètement les modules ECMAScript (ESM), offrant de meilleures performances et une compatibilité avec les standards modernes.
Principales Améliorations
- Support ESM natif pour une meilleure performance
- IoC Container simplifié et plus puissant
- TypeScript amélioré avec une meilleure inférence de types
- CLI modernisé avec de nouvelles commandes
- Architecture modulaire plus flexible
Installation et Premiers Pas
Création d'un Nouveau Projet
# Installation globale du CLI (optionnel)
npm i -g @adonisjs/cli
# Création d'un nouveau projet
npm init adonisjs@latest mon-projet-adonis
# Ou directement avec npx
npx create-adonisjs@latest mon-projet-adonis
Structure du Projet
mon-projet-adonis/
├── app/
│ ├── controllers/
│ ├── middleware/
│ ├── models/
│ ├── services/
│ └── validators/
├── config/
├── database/
│ ├── migrations/
│ └── seeders/
├── public/
├── resources/
│ └── views/
├── routes/
├── tests/
├── ace.js
├── server.ts
└── package.json
Configuration de Base
// server.ts
import { Ignitor, prettyPrintError } from '@adonisjs/core'
const ignitor = new Ignitor(new URL('./', import.meta.url))
try {
await ignitor.httpServer().start()
} catch (error) {
process.exitCode = 1
prettyPrintError(error)
}
L'ORM Lucid : L'Eloquent de JavaScript
Lucid est l'ORM d'AdonisJS, inspiré d'Eloquent. Il offre une syntaxe expressive et intuitive.
Création d'un Modèle
node ace make:model User
node ace make:migration create_users_table
Modèle User
// app/models/user.ts
import { DateTime } from 'luxon'
import { BaseModel, column, hasMany } from '@adonisjs/lucid/orm'
import type { HasMany } from '@adonisjs/lucid/types/relations'
import Post from './post.js'
export default class User extends BaseModel {
@column({ isPrimary: true })
declare id: number
@column()
declare email: string
@column({ serializeAs: null })
declare password: string
@column()
declare fullName: string
@column.dateTime({ autoCreate: true })
declare createdAt: DateTime
@column.dateTime({ autoCreate: true, autoUpdate: true })
declare updatedAt: DateTime
@hasMany(() => Post)
declare posts: HasMany<typeof Post>
}
Migration
// database/migrations/create_users_table.ts
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'users'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id')
table.string('email').notNullable().unique()
table.string('password').notNullable()
table.string('full_name').notNullable()
table.timestamp('created_at')
table.timestamp('updated_at')
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
Routage Expressif et Puissant
Le système de routage d'AdonisJS est à la fois simple et puissant.
Routes de Base
// routes/web.ts
import router from '@adonisjs/core/services/router'
import { middleware } from './kernel.js'
// Route simple
router.get('/', async () => {
return { hello: 'world' }
})
// Routes avec paramètres
router.get('/users/:id', 'UsersController.show')
router.post('/users', 'UsersController.store')
// Groupes de routes
router.group(() => {
router.get('/profile', 'UsersController.profile')
router.put('/profile', 'UsersController.updateProfile')
router.delete('/account', 'UsersController.destroy')
}).prefix('/api/v1').middleware(middleware.auth())
// Routes avec middleware
router.group(() => {
router.resource('/posts', 'PostsController')
}).middleware([middleware.auth(), middleware.verified()])
Route Resource (comme Laravel)
// Génère automatiquement les routes CRUD
router.resource('/posts', 'PostsController')
// Équivalent à :
// GET /posts -> PostsController.index
// GET /posts/create -> PostsController.create
// POST /posts -> PostsController.store
// GET /posts/:id -> PostsController.show
// GET /posts/:id/edit -> PostsController.edit
// PUT /posts/:id -> PostsController.update
// DELETE /posts/:id -> PostsController.destroy
Controllers Robustes
Les controllers dans AdonisJS suivent le pattern MVC classique.
Création d'un Controller
node ace make:controller PostsController --resource
Controller Complet
// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
import Post from '#models/post'
import { createPostValidator, updatePostValidator } from '#validators/post'
export default class PostsController {
/**
* Afficher la liste des posts
*/
async index({ request, response }: HttpContext) {
const page = request.input('page', 1)
const limit = request.input('limit', 10)
const posts = await Post.query()
.preload('author')
.paginate(page, limit)
return response.ok(posts)
}
/**
* Afficher un post spécifique
*/
async show({ params, response }: HttpContext) {
const post = await Post.query()
.where('id', params.id)
.preload('author')
.preload('comments', (query) => {
query.preload('user')
})
.firstOrFail()
return response.ok(post)
}
/**
* Créer un nouveau post
*/
async store({ request, response, auth }: HttpContext) {
const payload = await request.validateUsing(createPostValidator)
const post = await Post.create({
...payload,
userId: auth.user!.id,
})
await post.load('author')
return response.created(post)
}
/**
* Mettre à jour un post
*/
async update({ params, request, response, bouncer }: HttpContext) {
const post = await Post.findOrFail(params.id)
await bouncer.authorize('updatePost', post)
const payload = await request.validateUsing(updatePostValidator)
post.merge(payload)
await post.save()
return response.ok(post)
}
/**
* Supprimer un post
*/
async destroy({ params, response, bouncer }: HttpContext) {
const post = await Post.findOrFail(params.id)
await bouncer.authorize('deletePost', post)
await post.delete()
return response.noContent()
}
}
Validation de Données Robuste
AdonisJS utilise VineJS pour la validation, offrant une API moderne et type-safe.
Création d'un Validator
node ace make:validator CreatePost
Validator Personnalisé
// app/validators/post.ts
import vine from '@vinejs/vine'
export const createPostValidator = vine.compile(
vine.object({
title: vine.string().minLength(3).maxLength(100),
content: vine.string().minLength(10),
categoryId: vine.number().exists(async (db, value) => {
const category = await db.from('categories').where('id', value).first()
return !!category
}),
tags: vine.array(vine.string()).optional(),
publishedAt: vine.date().optional(),
isPublished: vine.boolean().optional(),
})
)
export const updatePostValidator = vine.compile(
vine.object({
title: vine.string().minLength(3).maxLength(100).optional(),
content: vine.string().minLength(10).optional(),
categoryId: vine.number().exists(async (db, value) => {
const category = await db.from('categories').where('id', value).first()
return !!category
}).optional(),
tags: vine.array(vine.string()).optional(),
publishedAt: vine.date().optional(),
isPublished: vine.boolean().optional(),
})
)
Authentification Simplifiée
AdonisJS propose plusieurs méthodes d'authentification prêtes à l'emploi.
Configuration de l'Authentification
node ace add @adonisjs/auth
Méthodes d'Authentification Disponibles
// config/auth.ts
import { defineConfig } from '@adonisjs/auth'
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
import { jwtGuard, jwtUserProvider } from '@adonisjs/auth/jwt'
const authConfig = defineConfig({
default: 'web',
guards: {
// Authentification par session (web)
web: sessionGuard({
useRememberMeTokens: true,
provider: sessionUserProvider({
model: () => import('#models/user'),
}),
}),
// Authentification JWT (API)
api: jwtGuard({
provider: jwtUserProvider({
model: () => import('#models/user'),
}),
}),
},
})
export default authConfig
Controller d'Authentification
// app/controllers/auth_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
import { loginValidator, registerValidator } from '#validators/auth'
export default class AuthController {
async register({ request, response }: HttpContext) {
const payload = await request.validateUsing(registerValidator)
const user = await User.create(payload)
return response.created({ user })
}
async login({ request, response, auth }: HttpContext) {
const { email, password } = await request.validateUsing(loginValidator)
const user = await User.verifyCredentials(email, password)
const token = await auth.use('api').generate(user)
return response.ok({
user,
token: token.value!.release(),
})
}
async logout({ response, auth }: HttpContext) {
await auth.use('api').revoke()
return response.ok({ message: 'Déconnexion réussie' })
}
async me({ response, auth }: HttpContext) {
await auth.check()
return response.ok({ user: auth.user })
}
}
Middleware Puissants
Les middleware permettent de traiter les requêtes à différents niveaux.
Middleware d'Autorisation
// app/middleware/admin_middleware.ts
import type { HttpContext } from '@adonisjs/core/http'
import type { NextFn } from '@adonisjs/core/types/http'
export default class AdminMiddleware {
async handle({ auth, response }: HttpContext, next: NextFn) {
await auth.check()
if (!auth.user?.isAdmin) {
return response.forbidden({
message: 'Accès refusé. Droits administrateur requis.'
})
}
return await next()
}
}
Middleware de Rate Limiting
node ace add @adonisjs/limiter
// app/middleware/throttle_middleware.ts
import { throttle } from '@adonisjs/limiter/services/main'
export const apiThrottle = throttle({
key: (ctx) => ctx.request.ip(),
allowedRequests: 100,
blockDurationInMs: 60 * 1000, // 1 minute
})
CLI Ace : L'Artisan d'AdonisJS
Le CLI Ace offre de nombreuses commandes pour accélérer le développement.
Commandes Essentielles
# Créer des éléments
node ace make:controller UserController
node ace make:model Post
node ace make:middleware Auth
node ace make:validator CreateUser
node ace make:service EmailService
# Base de données
node ace migration:run
node ace migration:rollback
node ace db:seed
node ace db:fresh
# Développement
node ace serve --watch
node ace build
node ace repl
# Tests
node ace test
node ace test --watch
Commande Personnalisée
// commands/send_newsletter.ts
import { BaseCommand } from '@adonisjs/ace'
import type { CommandOptions } from '@adonisjs/ace/types'
export default class SendNewsletter extends BaseCommand {
static commandName = 'newsletter:send'
static description = 'Envoyer la newsletter aux abonnés'
static options: CommandOptions = {
startApp: true,
}
async run() {
const { default: User } = await import('#models/user')
const { default: MailService } = await import('#services/mail_service')
const subscribers = await User.query().where('isSubscribed', true)
this.logger.info(`Envoi de la newsletter à ${subscribers.length} abonnés`)
for (const user of subscribers) {
await MailService.sendNewsletter(user)
this.logger.info(`Newsletter envoyée à ${user.email}`)
}
this.logger.success('Newsletter envoyée avec succès !')
}
}
Services et Injection de Dépendances
AdonisJS utilise un IoC Container puissant pour la gestion des dépendances.
Service Personnalisé
// app/services/email_service.ts
import { inject } from '@adonisjs/core'
import mail from '@adonisjs/mail/services/main'
@inject()
export default class EmailService {
constructor(private logger: Logger) {}
async sendWelcomeEmail(user: User) {
try {
await mail.send((message) => {
message
.to(user.email)
.subject('Bienvenue sur notre plateforme !')
.htmlView('emails/welcome', { user })
})
this.logger.info(`Email de bienvenue envoyé à ${user.email}`)
} catch (error) {
this.logger.error('Erreur lors de l\'envoi de l\'email', error)
throw error
}
}
async sendPasswordResetEmail(user: User, resetToken: string) {
const resetUrl = `${env.get('APP_URL')}/reset-password?token=${resetToken}`
await mail.send((message) => {
message
.to(user.email)
.subject('Réinitialisation de votre mot de passe')
.htmlView('emails/password_reset', { user, resetUrl })
})
}
}
Utilisation dans un Controller
// app/controllers/users_controller.ts
import { inject } from '@adonisjs/core'
import EmailService from '#services/email_service'
@inject()
export default class UsersController {
constructor(private emailService: EmailService) {}
async store({ request, response }: HttpContext) {
const payload = await request.validateUsing(createUserValidator)
const user = await User.create(payload)
// Envoi de l'email de bienvenue
await this.emailService.sendWelcomeEmail(user)
return response.created(user)
}
}
Tests Intégrés avec Japa
AdonisJS intègre Japa, un framework de tests moderne et puissant.
Test d'API
// tests/functional/posts.spec.ts
import { test } from '@japa/runner'
import { ApiClient } from '@japa/api-client'
import User from '#models/user'
import Post from '#models/post'
test.group('Posts API', (group) => {
let user: User
let authToken: string
group.setup(async () => {
user = await User.create({
email: 'test@example.com',
password: 'password123',
fullName: 'Test User'
})
// Simulation de l'authentification
const response = await new ApiClient().post('/api/auth/login').json({
email: 'test@example.com',
password: 'password123'
})
authToken = response.body().token
})
test('should get posts list', async ({ client }) => {
const response = await client
.get('/api/posts')
.header('Authorization', `Bearer ${authToken}`)
response.assertStatus(200)
response.assertBodyContains({ meta: { total: 0 } })
})
test('should create a new post', async ({ client }) => {
const postData = {
title: 'Mon premier post',
content: 'Contenu de mon premier post de test',
categoryId: 1
}
const response = await client
.post('/api/posts')
.header('Authorization', `Bearer ${authToken}`)
.json(postData)
response.assertStatus(201)
response.assertBodyContains({
title: postData.title,
content: postData.content
})
})
test('should update a post', async ({ client }) => {
const post = await Post.create({
title: 'Post original',
content: 'Contenu original',
userId: user.id,
categoryId: 1
})
const updateData = {
title: 'Post mis à jour',
content: 'Contenu mis à jour'
}
const response = await client
.put(`/api/posts/${post.id}`)
.header('Authorization', `Bearer ${authToken}`)
.json(updateData)
response.assertStatus(200)
response.assertBodyContains(updateData)
})
})
Test Unitaire
// tests/unit/email_service.spec.ts
import { test } from '@japa/runner'
import EmailService from '#services/email_service'
import User from '#models/user'
test.group('Email Service', () => {
test('should send welcome email', async ({ assert }) => {
const emailService = new EmailService()
const user = new User()
user.email = 'test@example.com'
user.fullName = 'Test User'
// Mock du service mail
const mockSend = vi.fn()
vi.mock('@adonisjs/mail/services/main', () => ({
send: mockSend
}))
await emailService.sendWelcomeEmail(user)
assert.isTrue(mockSend.calledOnce)
})
})
Déploiement et Production
Build pour la Production
# Build de l'application
node ace build
# Démarrage en production
cd build
npm ci --production
node bin/server.js
Configuration Docker
# Dockerfile
FROM node:20-alpine
WORKDIR /app
# Copie des fichiers de dépendances
COPY package*.json ./
RUN npm ci --only=production
# Copie du code source
COPY . .
# Build de l'application
RUN node ace build
# Exposition du port
EXPOSE 3333
# Commande de démarrage
CMD ["node", "build/bin/server.js"]
Variables d'Environnement
# .env.production
NODE_ENV=production
PORT=3333
APP_KEY=your-secret-app-key
DB_CONNECTION=pg
PG_HOST=localhost
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=password
PG_DB_NAME=production_db
REDIS_CONNECTION=main
REDIS_HOST=localhost
REDIS_PORT=6379
MAIL_MAILER=smtp
AdonisJS vs Express vs NestJS
Comparaison Rapide
| Fonctionnalité | AdonisJS | Express | NestJS |
|---|---|---|---|
| Architecture | MVC Full-Stack | Minimaliste | Architecture modulaire |
| TypeScript | ✅ Natif | ⚠️ Configuration | ✅ Natif |
| ORM | ✅ Lucid inclus | ❌ À ajouter | ⚠️ TypeORM/Prisma |
| Auth | ✅ Intégré | ❌ À implémenter | ⚠️ Packages tiers |
| Validation | ✅ VineJS inclus | ❌ À ajouter | ✅ Class-validator |
| CLI | ✅ Ace puissant | ❌ Basique | ✅ Très complet |
| Courbe d'apprentissage | 📈 Modérée | 📈 Facile | 📈 Difficile |
Écosystème et Packages Officiels
AdonisJS propose un écosystème riche de packages officiels :
- @adonisjs/lucid - ORM et Query Builder
- @adonisjs/auth - Authentification
- @adonisjs/mail - Envoi d'emails
- @adonisjs/redis - Client Redis
- @adonisjs/session - Gestion des sessions
- @adonisjs/shield - Sécurité CSRF, CSP
- @adonisjs/limiter - Rate limiting
- @adonisjs/drive - Système de fichiers
- @adonisjs/attachment-lite - Upload de fichiers
Cas d'Usage Idéaux
AdonisJS excelle dans ces scenarios :
1. APIs REST Robustes
Parfait pour créer des APIs avec authentification, validation et base de données.
2. Applications Full-Stack
Idéal quand vous voulez un backend et frontend intégrés.
3. Prototypage Rapide
Convention over configuration permet de démarrer rapidement.
4. Migration depuis Laravel
Courbe d'apprentissage douce pour les développeurs Laravel.
5. Applications d'Entreprise
Architecture solide et patterns éprouvés.
Communauté et Ressources
- Documentation officielle : https://docs.adonisjs.com
- Discord communautaire très actif
- GitHub : https://github.com/adonisjs
- Twitter : @adonisframework
- Packages tiers en croissance constante
Conclusion
AdonisJS offre un ensemble complet de fonctionnalités prêtes à l'emploi tout en permettant d'installer uniquement les modules nécessaires, ce qui en fait un choix excellent pour les développeurs qui :
✅ Viennent de Laravel et veulent retrouver cette productivité en JavaScript
✅ Cherchent un framework complet plutôt que d'assembler de multiples packages
✅ Privilégient TypeScript et la type-safety
✅ Veulent une architecture MVC éprouvée
✅ Ont besoin de fonctionnalités comme l'ORM, l'auth, la validation out-of-the-box
AdonisJS n'est peut-être pas le framework Node.js le plus populaire, mais il est certainement l'un des plus productifs et bien conçus. Si vous cherchez une alternative moderne à Express qui ne vous oblige pas à réinventer la roue à chaque projet, AdonisJS mérite définitivement votre attention.
La version 6 marque une étape importante dans la maturité du framework, avec l'adoption complète des modules ECMAScript (ESM) et des améliorations significatives en termes de performances et d'expérience développeur.
Prêt à essayer AdonisJS ? Commencez par créer un petit projet API et découvrez par vous-même pourquoi de plus en plus de développeurs adoptent ce "Laravel de JavaScript" !
Partagez vos expériences avec AdonisJS dans les commentaires et n'hésitez pas à poser vos questions !

Besoin d'un développeur pour votre prochain projet ? Je suis disponible pour des missions freelance.
Me contacterArticles similaires
Related writings that dive deeper into design decisions, workflows, and creative problem-solving. Each article expands on ideas shared throughout this project.

