Getting started
Directory structure
A new Oriel app has Laravel's layout: your code in app, your settings in config, your routes in routes, and a
few folders that Oriel reads by itself.
Introduction#
The layout is a starting point, not a rule: your files import each other by relative path, so a class can live wherever suits your app. A few folders are the exception. Oriel looks in them by name to find your models, your commands, your listeners and your policies, as Folders Oriel discovers lists.
Every starter kit is built from layers: base, which every app has, then the layers of its kit. The
starter kits' layers section says which folders each layer adds.
The root directory#
The app directory#
app holds the core code of your app: its controllers, models, providers and most of its other classes. The
app directory section looks inside it.
The bootstrap directory#
bootstrap/ creates your app: it names your route files, configures middleware and error handling, and lists your
service providers through bootstrap/. Your server, your oriel command and your tests all
start from it.
The Inertia kits with server-side rendering build their SSR bundle into bootstrap/, which git ignores. There is
no bootstrap/: Oriel has no route or config cache to store.
The config directory#
config holds your app's configuration files, one TypeScript module per part of the framework.
The database directory#
database holds your migrations (database/), your model factories (database/) and your seeders
(database/). A new app keeps its SQLite database here too, in database/, which git ignores.
The public directory#
public holds the files the server sends as they are, such as favicon.svg, and public/, the entry point
that runs your app in production (see Deployment). A request for a file that exists in public gets
the file before your routes run. TypeScript files and dotfiles there are never sent.
Vite builds your scripts and styles into public/, and while npm run dev runs it writes public/, which
tells your pages to load their assets from Vite. node oriel storage:link adds public/, a link to
storage/. Git ignores all three.
The resources directory#
resources holds your views and the uncompiled sources of your pages:
resources/: your views, written in TSX, such asviews welcome.tsx. In the Inertia kits,app.tsxthere is the root view every page is rendered into.resources/: the kits' stylesheet, with Tailwind and the Oriel theme.css/ app.css resources/: your pages' scripts. In the Inertia kits, the pages are injs resources/, with theirjs/ pages componentsandlayoutsbeside them.resources/: the route and page types thatjs/ oriel route:typesandinertia:typeswrite, which git ignores.
The API kit has no resources folder until npm run typecheck writes resources/.
The routes directory#
routes holds your route files. A new app has two:
routes/: the routes of your pages, in theweb.ts webmiddleware group, which gives them the session, cookie encryption and CSRF protection.routes/: your closure commands, such as theconsole.ts inspirecommand a new app comes with, and your scheduled tasks.
The kits with pages add routes/, for registration, signing in and out, password resets and email
verification, and routes/, for the settings pages. The API kit has routes/ in place of
routes/: its routes are stateless, their URIs start with /api, and their users sign in with tokens.
node oriel install:api adds a routes/ to another app. bootstrap/ lists the files to load (see
Routing).
The storage directory#
storage holds the files your app and the framework write:
storage/: theapp/ private localdisk, for files your app keeps to itself.storage/: theapp/ public publicdisk, for files anyone may download, such as avatars.node oriel storage:linklinkspublic/to it.storage storage/: theframework/ cache/ data filecache store.storage/: theframework/ sessions filesession driver's sessions.storage/: kept from Laravel's layout. Oriel's views are TSX modules, so nothing compiles into it.framework/ views storage/: your logs,logs oriel.log, andmail.logwhen mail is logged to its own channel.
Git keeps the folders and ignores what is written into them.
The tests directory#
tests holds your tests: tests/ for tests that send requests to your app or run its commands, and tests/
for the rest, with tests/, the class they boot the app with. A test file's name ends in .test.ts, or
.test.tsx. Run them with node oriel test, or with npm test, and on Bun with npm run test:bun.
The types directory#
types holds the type declarations Oriel writes for your app:
types/: your models' columns, written bymodels.d.ts node oriel model:typesfrom your database.migrate,migrate:freshandmigrate:refreshwrite it again when they finish, outside production. It is in git, so your app type-checks on a fresh clone.types/: your route names and parameters, written byroutes.d.ts node oriel route:types. Git ignores it.
The node_modules directory#
node_modules holds your dependencies, as vendor does in a Laravel app. Your package manager writes it, and git
ignores it.
The files at the root#
| File | What it is |
|---|---|
oriel | Your app's command line: node oriel <command>, or bun oriel <command> |
.env, .env.example | Your environment's values, and the list of the variables your app reads (see Configuration) |
package.json | Your dependencies and scripts, such as dev, build, start, test, test:bun and typecheck |
tsconfig.json | TypeScript's settings for your server code; the kits' pages have their own in resources/ |
vite.config.ts | Vite's settings, with the oriel() plugin (not in the API kit) |
vitest.config.ts | Vitest's settings for your tests |
README.md | How to run the app, written for your kit |
.gitignore | What git leaves out |
.github/ | The CI workflow the installer writes for your package manager |
The app directory#
Most of your app lives in app. A new app has app/, with its base Controller, app/, with the User
model, and app/, with the AppServiceProvider. The other folders appear when a make: command writes a
class into them: app/ doesn't exist until you run make:command. node oriel list shows every make:
command.
The Console directory#
app/ holds your console commands, written by make:command. Oriel
finds them by itself.
The Events directory#
app/ holds your event classes, written by make:event.
The Http directory#
app/ holds what handles a request: Controllers (make:controller), Middleware (make:middleware), form
Requests (make:request) and API Resources (make:resource).
The Jobs directory#
app/ holds your queued jobs, written by make:job.
The Listeners directory#
app/ holds the classes that handle your events, written by make:listener. Oriel finds each one by itself,
and registers it for the events its static listensTo names.
The Live directory#
app/ holds the Live kit's components, and the ones make:live writes. Each component's name comes from
its path: app/ is auth.login.
The Mail directory#
app/ holds your mail classes, written by make:mail, which also writes the mail's view in
resources/.
The Models directory#
app/ holds your models, written by make:model. Oriel finds them by itself: a route parameter
named after a model receives it, and model:types writes their columns.
The Notifications directory#
app/ holds your notifications, written by make:notification.
The Policies directory#
app/ holds your authorization policies, written by make:policy. A
policy named after a model, as PostPolicy for Post, applies to that model without being registered.
The Providers directory#
app/ holds your service providers. A new app has AppServiceProvider. make:provider writes
a new one there, which you then add to the list in bootstrap/.
The Rules directory#
app/ holds your validation rule objects, written by make:rule.
The other directories#
make:cast writes into app/ and make:observer into app/. The kits with pages also have
app/, which builds the dashboard's checklist.
Folders Oriel discovers#
A TypeScript module runs only when something imports it, so Oriel imports these folders itself, and registers what it finds there:
| Folder | What Oriel registers | When |
|---|---|---|
app/ | Every exported model, for route model binding by name, model:types, and the queue and Live, which store a model as its class and key | When the app boots |
app/ | Each <Model>Policy file's policy, for the model of that name (only the folder's top level) | When the app boots |
app/ | Every listener with a static listensTo, for the events it names | When the app boots |
app/ | Every component, under the name its path gives it | When the app boots |
app/ | Every command class | When an oriel command or a test runs |
database/ | Every factory, for its model's factory() (only the folder's top level) | When an oriel command or a test runs |
app/, app/, app/, app/, app/ | The classes a queued job carries, so the worker can rebuild them | When queue:work starts |
Each folder is read with the folders inside it, except app/ and database/. A class in another
folder works, but isn't discovered: register it yourself, as Event.listen() does for a listener or Gate.policy()
for a policy.
Other folders are read when they are needed: config when the app is created, resources/ for each view,
database/ by migrate, and database/ by db:seed.
The starter kits' layers#
Each kit is the base layer and its own layers, applied in order, a later layer's file replacing an earlier one's:
| Kit | Layers |
|---|---|
| React, Vue, Svelte, Solid, Angular | base, web, inertia, then react, vue, svelte, solid or angular |
| Live | base, web, live |
| API | base, api |
What each layer adds:
| Layer | Adds |
|---|---|
base | The skeleton of every app: app/, app/, app/, bootstrap, config, database, public, resources/, routes/ and routes/, storage, tests, types, and the root files |
web | What the kits with pages share: the email verification controller, the HandleAppearance middleware, app/, resources/, the browser scripts in resources/ (appearance.ts, checklist.ts, menus.ts, names.ts) and resources/ |
inertia | The Inertia kits' server side: the auth, dashboard and settings controllers, HandleInertiaRequests, the form requests, config/, bootstrap/, and routes/, routes/ and routes/ |
react, vue, svelte, solid, angular | The pages, layouts and components in resources/, the browser entry and, except in Angular, the SSR entry, the root view resources/, vite.config.ts and the kit's README.md |
live | The components in app/, their views and view components in resources/, resources/, bootstrap/, the three route files, vite.config.ts and the kit's README.md |
api | The token auth controllers, the login request, bootstrap/, routes/ and the kit's README.md; it removes routes/, resources/ and the welcome page's test |
Each layer but inertia also adds to package.json (web its dev dependencies only), and all but the five framework
layers add their tests.
Starter kits describes what the kits do with them.
Generated and ignored files#
Some files are written by a command rather than by you. Don't edit them: run the command again.
| File | Written by | In git |
|---|---|---|
types/ | model:types, and migrate outside production | Yes |
types/ | route:types | No |
resources/ | route:types, and the Inertia kits' Vite plugin | No |
resources/ | inertia:types, and the Inertia kits' Vite plugin | No |
public/ | npm run build | No |
public/ | npm run dev, while it runs | No |
bootstrap/ | npm run build in the kits with server-side rendering | No |
public/ | storage:link | No |
database/ | The first connection to it, such as migrate | No |
.env | The installer, from .env.example | No |
Git also ignores node_modules, the files under storage, .env.backup, .DS_Store and Yarn's
.yarn/.