· frameworks  · 5 min read

Unleashing the Power of AdonisJS: Top 5 Tips for New Developers

Practical, hands-on tips for developers starting with AdonisJS - learn TypeScript-first patterns, Lucid ORM best practices, validation, auth & permissions, testing, performance, and common pitfalls to avoid.

Practical, hands-on tips for developers starting with AdonisJS - learn TypeScript-first patterns, Lucid ORM best practices, validation, auth & permissions, testing, performance, and common pitfalls to avoid.

Introduction

AdonisJS is a TypeScript-first, batteries-included Node.js framework that gives you a structured, productive environment for building web apps and APIs. If you’re new to AdonisJS, you can move quickly - but there are a few patterns and pitfalls every newcomer should learn to get the most out of the framework.

This article walks through the top five practical tips for new AdonisJS developers, with examples, common mistakes, and links to the official docs so you can dig deeper.

Why AdonisJS matters for new projects

  • TypeScript-first developer experience with typed models, controllers, and requests.
  • Built-in pieces for common needs: routing, middleware, authentication, authorization (Bouncer), validation, ORM (Lucid), queues, caching, and testing.
  • Conventions that reduce decision fatigue and speed up development.

If you already know Express or another Node framework, think of Adonis as a higher-level framework that helps keep projects consistent and maintainable.


Tip 1 - Embrace the TypeScript-first structure and the IoC container

AdonisJS is opinionated about project structure (folders like app, start, config, providers) and uses an IoC container to resolve dependencies. Learning those conventions pays off quickly.

Why it helps:

  • Easy discoverability: controllers live in app/Controllers/Http, models in app/Models, middleware in app/Middleware.
  • Providers and bindings let you register and replace services without touching application code.
  • Type safety reduces runtime errors and gives better IDE completion.

Quick examples:

  • Register middleware in start/kernel.ts (this is where route/global middleware is configured).

  • Use dependency injection via the IoC container by importing with the @ioc: alias, e.g.:

import Database from '@ioc:Adonis/Lucid/Database';

Common mistakes to avoid:

  • Bypassing the IoC container frequently (e.g., require/import hacks) - this reduces testability.
  • Mutating global state in providers or models - keep services stateless or thread-safe.

Docs: https://docs.adonisjs.com


Tip 2 - Master Lucid ORM: relationships, eager loading, and transactions

Lucid is Adonis’s ORM and gives you typed models and a fluent query builder. Learn these fundamentals early:

  • Models and relationships (hasMany, belongsTo, manyToMany).
  • Preloading (eager loading) to avoid N+1 queries.
  • Transactions for multi-step writes.
  • Pagination and query scopes.

Examples:

Eager loading to avoid N+1:

// Bad (N+1): calling .related for each user
const users = await User.all();
for (const u of users) {
  await u.related('posts').query(); // causes N+1 queries
}

// Good: preload posts on the initial query
const usersWithPosts = await User.query().preload('posts');

Using transactions (pattern):

import Database from '@ioc:Adonis/Lucid/Database';

const trx = await Database.transaction();
try {
  // perform multiple operations that should be atomic
  await user.useTransaction(trx).save();
  await order.useTransaction(trx).save();
  await trx.commit();
} catch (error) {
  await trx.rollback();
  throw error;
}

Tips:

  • Use preload() for relations you know you’ll need; avoid over-eager preloading large collections.
  • Prefer database transactions for multi-step operations that must be atomic.
  • Use query scopes to encapsulate frequently used query logic.

Docs: https://docs.adonisjs.com/guides/lucid


Tip 3 - Validate and sanitize early: use the Validator and request schemas

Adonis comes with a powerful validator that integrates nicely with TypeScript. Validate and sanitize input in request handlers or dedicated validator classes.

Why:

  • Avoid invalid data at the boundary of your application.
  • Keep controllers thin and focused on orchestration.
  • Provide consistent error messages to API clients.

Example using the validator in a controller:

import { schema, rules } from '@ioc:Adonis/Core/Validator';

const registerSchema = schema.create({
  email: schema.string({}, [rules.email()]),
  password: schema.string({}, [rules.minLength(8)]),
  fullName: schema.string.optional(),
});

// In controller action
const payload = await request.validate({ schema: registerSchema });
// payload is typed according to schema and safe to use

Best practices:

  • Create dedicated validator files or classes for complex validations.
  • Sanitize incoming payloads so you don’t accidentally allow untrusted fields to be mass-assigned to models.
  • Return user-friendly validation errors and log server-side validation failures for debugging.

Docs: https://docs.adonisjs.com/guides/validator


Tip 4 - Use built-in Auth, Bouncer, and middleware for guardrails

Authentication and authorization are easy to get wrong. Adonis gives you:

  • Auth providers (JWT, session-based, etc.).
  • Bouncer for expressive authorization policies.
  • Route middleware for enforcing authentication and roles.

Simple route protection:

// routes.ts
Route.get('/dashboard', 'DashboardController.index').middleware(['auth']);

Using Bouncer for authorization (concept):

// define a policy or ability in Bouncer
// then check it in a controller or middleware
await bouncer.authorize('updatePost', post);

Tips:

  • Always protect sensitive routes with middleware or Bouncer checks - don’t rely only on controller logic.
  • Use guards when your app needs multiple auth strategies (API tokens + session, etc.).
  • Keep authorization rules in policies or Bouncer files to centralize access logic.

Docs: https://docs.adonisjs.com/guides/auth and https://docs.adonisjs.com/guides/bouncer


Tip 5 - Test early, optimize smartly, and prepare for production

Testing and performance tuning are often postponed - but small investments up front pay big dividends.

Testing:

  • Use Adonis’s preferred test runner (Japa) and write unit and integration tests for controllers, models, and services.
  • Mock external services and use test databases or transactions to keep tests isolated.

Performance & operations:

  • Cache heavy or frequently read queries with Redis (e.g., query results, computed counters).
  • Push long-running work to a queue/worker instead of blocking requests.
  • Monitor DB queries for slow statements and use indexes where appropriate.
  • Use connection pooling and graceful shutdown to avoid dropped requests during deploys.

Deployment checklist:

  • Never store secrets in source - use environment variables and a secrets manager.
  • Configure CORS and security headers.
  • Use a process manager like PM2, Docker, or a platform provider; enable zero-downtime deploys where possible.

Docs & tools:


Common pitfalls and how to avoid them

  • Over-eager preloading: preload only what you need to avoid memory/DB blowups.
  • Ignoring TypeScript types: embrace typed contracts for controllers, models, and services to catch bugs early.
  • Not using transactions: for multi-step updates, always use transactions to prevent partial writes.
  • Exposing raw SQL or interpolated queries - prefer parameterized queries and the query builder to avoid injection.
  • Not sanitizing input or mass-assigning model attributes - explicitly pick fields to assign or use model hooks carefully.

Quick actionable checklist for your first AdonisJS projects

  • Use TypeScript and learn the project layout (app, start, providers, config).
  • Write request validators and sanitize inputs.
  • Learn Lucid relationships, use preload() and transactions.
  • Protect routes with auth middleware and centralize authorization with Bouncer.
  • Write tests (unit + integration) early with Japa.
  • Add caching/queues for expensive or asynchronous tasks.
  • Use environment variables for secrets and set up monitoring/logging.

Further reading and references

Summary

AdonisJS helps you build maintainable, well-structured Node.js applications quickly. For new developers: learn the conventions, embrace TypeScript, master Lucid, validate inputs, centralize auth/authorization, and invest in tests and production readiness. Follow these tips and you’ll avoid common mistakes while maximizing Adonis’s productivity advantages.

Back to Blog

Related Posts

View All Posts »