Our application starts in the bin directory. It contains an entry point file for the three different types of environments our server can start within.
Console, for Ace CLI commands
Server, for our HTTP server
Test, for testing
Unless you're doing something advanced, you won't need to give much thought to this directory. Once here, we enter the boot phase.
As part of this, our adonisrc.ts file is read. This file is within the root of our project and is a primary point where things get registered for inclusion within our project. It contains things like:
Assembler Hooks - hooks run by the assembler (like generated files)
Commands from packages
Service Providers - registers providers to hook into the lifecycle
Preload files - registers files to be run during the start phase
Test suites - registers suites or types of tests used in our application
Meta files - registers files to be copied to production builds
Config Files
Next, the configuration files within our application will be included. These can be found in the config folder. There's an app config for general settings for our HTTP server, auth for authentication, database for database configuration and so on.
Service Providers
Registered Service Providers are also read here. Service Providers are classes containing lifecycle hooks, allowing them to perform code at these various stages of our application. Below is an example of an empty Service Provider class.
import type { ApplicationService } from '@adonisjs/core/types'export default class ExampleProvider { 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() {} /** * Preparing to shutdown the app */ async shutdown() {}}
Copied!
The boot phase will run the register then boot methods in the order defined within the adonisrc.ts providers array. We'll touch on these as part of the last module in this series, but they can be found within the providers folder. This folder isn't included in our project structure until we create a provider.
Start Phase
The start phase is where things begin to get initialized. This is where the start directory shines, as its general purpose is to hold files that should be preloaded as part of the start process, like our route definitions, even listeners, and middleware registrations.
By default, we're started with three files here:
env.ts holds environment variable type definitions
kernel.ts is where our middleware is registered
routes.ts is where our routes are defined
Files from this directory that we want to run need to be explicitly included within the preloads array in our adonisrc.ts file. Note, these files are imported in parallel and may not execute in the order defined.
// adonisrc.tsexport default defineConfig({ // ... /* |-------------------------------------------------------------------------- | Preloads |-------------------------------------------------------------------------- | | List of modules to import before starting the application. | */ preloads: [ () => import('#start/routes'), () => import('#start/kernel'), () => import('#start/globals'), ], // ...})
Copied!
Additionally, during this phase the start then ready methods within Service Providers are also run.
Ready
Once the start phase is done, our server is ready to receive requests! This is where our application's domain logic comes into play.
App
The app directory holds our domain logic, like:
Controllers for handling route requests
Exceptions for handling application exceptions
Middleware for running logic between requests or responses
Models for integrating with our database
Validators for ensuring data validity before its reception
More can and will get added to this directory as we continue building an application as well.
Resources
When we server render views from our route handlers or controllers, those views and their assets get defined within our resources directory. When we opened http://localhost:3333 in our browser, the HTML page we ultimately saw is defined within here.
Ancillary Directories
That leaves the directories and files not specific to our dev server's lifecycle.
tests/ holds our test specifications and bootstrapping logic
database/ holds migrations, factories, and seeders used to shape our database and its initial data.
.adonisjs/ holds files generated by our server for type-safety and shouldn't be altered directly.
node_modules/ is where our project's dependencies are held
.env holds our environment variables
ace.js is a JavaScript entrypoint for the Ace CLI that imports the bin entrypoint
vite.config.js holds our Vite configuration for resourceful assets
tsconfig.json holds TypeScript's configuration
eslint.config.js holds ESLint's configuration
package.json holds NPM scripts and dependencies needed for our application, among other things
package-lock.json holds locked-in dependency versions so your whole team stays on the same versions.
.editorconfig is a config to hold presets for our text editor
.gitignore will inform Git to ignore certain files so they're excluded from our source control
.prettierignore tells Prettier to ignore certain files from its formatting