Directory Structure
A new Maat application separates reusable Dart code from the files that assemble and run the application. This keeps the runtime explicit while making controllers, services, and models easy to import and test.
The Application Root
The full application preset has this shape:
blog/├── bin/│ ├── maat.dart│ └── server.dart├── bootstrap/│ └── app.dart├── config/│ ├── app.dart│ ├── database.dart│ └── config.dart├── database/│ ├── migrations/│ └── seeders/├── lib/│ └── app/│ ├── console/│ ├── http/│ │ ├── controllers/│ │ ├── middleware/│ │ └── requests/│ └── providers/├── public/├── resources/│ ├── css/│ └── views/├── routes/│ ├── api.dart│ ├── channels.dart│ └── web.dart├── storage/│ └── logs/├── test/│ └── feature/├── .env├── .env.example├── Dockerfile└── pubspec.yamlThe --api preset omits public/, resources/, and the view configuration,
but keeps the same application lifecycle.
The lib/app Directory
Application classes live under lib/app and are imported with your package
name, such as package:blog/app/http/controllers/post_controller.dart.
| Directory | Responsibility |
|---|---|
console/commands |
Application-specific Sesh commands. |
http/controllers |
Request handlers grouped by feature. |
http/middleware |
Request and response pipeline behavior. |
http/requests |
Reusable authorization and validation rules. |
providers |
Container bindings and application boot logic. |
You may add directories such as models, services, or repositories. Maat
does not scan the filesystem, so the structure can follow your domain without
hidden registration behavior.
The bootstrap Directory
bootstrap/app.dart creates the application and declares its lifecycle:
Future<Application> createApp() => Application.configure( basePath: Platform.environment['APP_BASE_PATH'] ?? Directory.current.path, ) .withConfig(appConfig) .withProviders([ AppServiceProvider.new, DatabaseServiceProvider.new, (app) => RouteServiceProvider( app, api: apiRoutes, channels: channels, web: webRoutes, ), ]) .withMiddleware( (middleware) => middleware .use([PublicFiles(publicPath()), TrimStrings(), Cors()]) .alias({'throttle': ThrottleRequests.factory}), ) .withExceptions((exceptions) {}) .create();The generated application registers additional mail, notification, broadcasting, WebSocket, and view providers. They are omitted above so the request lifecycle stays visible.
Provider registration is ordered: every provider’s register() method runs
before any provider’s boot() method. See Service Providers
for the complete lifecycle.
The bin Directory
bin/server.dart builds the application and starts the HTTP server.
bin/maat.dart builds the same application and passes it to Sesh. Because both
entry points call createApp(), HTTP requests and console commands share the
same configuration and container bindings.
The config Directory
Each configuration file exports a map. config/config.dart imports those maps
and registers them under the keys used by config('name.key').
Configuration is outside lib because it assembles the application rather
than defining reusable package code. See Configuration.
The routes Directory
Route files keep endpoint declarations close together:
api.dartis mounted under/api.web.dartregisters browser routes without a prefix.channels.dartdefines private and presence-channel authorization.
The generated RouteServiceProvider loads all three files during boot.
Database, Resources, and Public Files
database/migrationscontains schema changes registered bydatabase/migrations.dart.database/seederscontains repeatable data setup.resources/viewscontains Khnum templates.resources/css/app.cssis the Tailwind source file.publiccontains files served directly, including compiled CSS and images.storage/logsholds file logs whenapp.log_pathis configured.
Generated CSS belongs in public/css and is normally ignored by Git. See
Static Files and Assets for serving and path-safety rules.
The test Directory
Feature tests build the real application through bootstrap/app.dart and send
requests with TestClient. Unit tests can import classes directly from
lib/app without booting the framework.
dart testSee Testing for HTTP assertions, database reset helpers, and framework fakes.
Why Some Directories Sit Outside lib
Dart treats lib/ as importable package code. Bootstrap, routes, configuration,
and migrations describe one application instance, so Maat keeps them at the
project root. This makes the dependency direction visible: entry points and
tests import application assembly files; reusable classes under lib/ do not
depend on how the process was started.