Skip to content
On this page

Modules overview ​

Adonia modules are domain slices the CLI copies into an AdonisJS host from the registry. Each module ships a service, typed contracts, and optional host stubs.

This page is the catalog for the bundled registry. It explains the difference between core packages and feature modules, how add copies files, and which modules depend on which.

Core packages versus feature modules ​

The registry splits packages into core (always present after init) and feature modules (you add them one at a time).

npx adonia init copies the core set into your host modules/ directory. Feature modules list their dependencies in module.jsonregistryDependencies. adonia add walks that graph and copies missing packages first.

NameKindRole
apiCoreShared envelopes, ApiService, ctx.respond, exception handler
typesCoreEnvelope and model TypeScript types
constantsCoreException codes and controller success codes
contractsCoreShared User / UserStore port
authFeatureRegistration, login, verification, password reset
accountFeatureProfile, email change, password change, deletion
notificationFeatureMulti-channel dispatcher with a host-owned registry
creemFeatureCreem checkout, portal, invoices, webhooks
subscriptionFeatureSubscription state synced from Creem webhooks

Core packages types, constants, and contracts don't have their own pages. They're documented with api, because add api pulls them in automatically.

NOTE

adonia list prints every name in the resolved registry and marks which ones are already in adonia.jsoninstalled.

How add copies a module ​

Plain adonia add <name> copies the domain slice only: the service, contracts, events, options, and module.json under modules/<name>/. Host files stay out of the way until you ask for them.

Opt-in flags copy stubs into the host tree. The flags stack:

  • --with-adapters copies Lucid/SDK adapters to app/adapters/.
  • --with-controllers copies controllers and implies adapters.
  • --with-validators copies Vine validators and providers/.
  • --with-models / --with-migrations copy Lucid models and migrations.
  • --with-routes copies start/routes/<name>.ts and the limiter example under start/. Pass --wire-routes to import that file from start/routes.ts.
  • --with-stubs copies models, migrations, controllers, validators, providers, start files, and adapters. It does not copy routes. Pass --with-routes as well when you want the example router file.

--with-tests copies the module's unit tests under modules/<name>/tests/. Host integration specs listed in hostTests stay in the registry as a reference; they are not copied by this flag.

IMPORTANT

Adonis packages used by stubs (@adonisjs/mail, @adonisjs/drive, @adonisjs/limiter) are not stubbed with no-ops. add and check warn when a copied stub needs a package that is missing from package.json and print node ace add @adonisjs/<pkg>.

See the add command for the full flag list.

Dependency graph ​

Feature modules never copy in isolation when a dependency is missing. add expands registryDependencies and prints a plan such as api → types → constants → contracts → auth.

text
api (+ types, constants, contracts)
 ├── auth
 │    └── account
 ├── notification
 └── creem
      └── subscription

Install in that order, or pass the leaf name and let the CLI pull parents. For example, adonia add account also installs api (and core) and auth if they aren't already in adonia.json.

Domain services versus host HTTP ​

Domain services return DTOs or void and throw ApiException. They don't wrap HTTP envelopes. Controllers in the host, or the optional stubs, call ApiService.prepareResponse / preparePaginatedResponse and ctx.respond.

Services that extend ApiService emit events through emitSafe. An event fires only when its name is listed in config/modules.ts under that module's emits array. add merges those names when the module declares events in module.json.

NotificationService is infrastructure, not a domain service. It doesn't extend ApiService and it doesn't emit domain events.

Shared user port ​

auth and account talk to a shared UserStore in #modules/contracts. Persistence, password hashing, and schema details stay in the host adapter. The Lucid adapter stub lives with auth; account reuses #adapters/lucid_user_store.

You must implement UserStore yourself if you skip --with-adapters.

Next steps ​

Pick a module and add it to a wired host:

  1. Finish getting started and host wiring if you haven't run npx adonia init --wire.
  2. Read api so you know the envelope and exception shape every other module uses.
  3. Add a feature module, starting with auth or notification.