Skip to content

Project Structure ​

A Holo-JS project is a normal Next.js, Nuxt, or SvelteKit app with a few extra folders: config/ for settings, server/ for backend code, and storage/ for local files. Holo finds your models, jobs, and other backend files by folder, so you don't register them by hand.

Directory tree ​

This is a project with every optional package installed. Folders for packages you didn't install are not created.

text
my-app/
├── config/                 # Settings for Holo and each package
│   ├── app.ts
│   ├── database.ts
│   ├── redis.ts
│   └── ...                 # auth.ts, queue.ts, mail.ts, storage.ts, ...
├── server/
│   ├── models/             # ORM models
│   ├── db/
│   │   ├── migrations/     # Table changes, run with `holo migrate`
│   │   ├── seeders/        # Sample and baseline data
│   │   ├── factories/      # Fake records for tests and seeding
│   │   └── observers/      # Model lifecycle hooks
│   ├── commands/           # Your own `holo` CLI commands
│   ├── jobs/               # Queue jobs
│   ├── events/             # Event definitions
│   ├── listeners/          # Event listeners
│   ├── policies/           # Authorization policies
│   ├── abilities/          # Authorization abilities
│   ├── mail/               # Mail definitions
│   ├── notifications/      # Notifications
│   ├── broadcast/          # Broadcast events
│   ├── channels/           # Broadcast channel authorization
│   └── realtime/           # Realtime query definitions
├── storage/                # SQLite database, uploaded files, sessions
├── .holo-js/               # Generated by Holo. Don't edit.
├── .env                    # Your local settings and secrets
├── .env.example            # The same keys, without secret values
├── package.json
├── tsconfig.json
├── eslint.config.mjs
└── ...                     # Your framework's files (see below)

What you edit and what Holo generates ​

You work in these places:

  • config/*.ts
  • .env and the other .env.* files
  • everything under server/
  • your framework's own files: pages, routes, layouts, components

Holo writes these, and rewrites them whenever your code changes:

  • .holo-js/generated/: registries of your models, jobs, events, and commands, the database types generated from your migrations, and config types.
  • .holo-js/framework/: scripts Holo uses to start your framework.
  • .holo-js/runtime/: scratch space for the CLI.

WARNING

Don't edit anything inside .holo-js/. Holo overwrites it on the next holo dev, holo build, or holo prepare. The whole folder is in .gitignore.

The config folder ​

Each file configures one feature. app.ts, database.ts, and redis.ts are always present. Installing a package adds its file, such as queue.ts or auth.ts. You can also add your own files. See Configuration.

The server folder ​

All of your backend code lives here.

FolderWhat goes in itLearn more
server/modelsdefineModel() definitions, one per fileORM
server/db/migrationsdefineMigration() files named with a timestamp prefixMigrations
server/db/seedersdefineSeeder() filesSeeding
server/db/factoriesFactories for generating fake recordsFactories
server/db/observersObservers that react to model eventsObservers
server/commandsCustom CLI commandsCustom Commands
server/jobsQueue jobsWriting Jobs
server/eventsEventsDefining Events
server/listenersListeners for those eventsListeners
server/policiesPer-model authorization policiesPolicies
server/abilitiesStandalone authorization checksAbilities
server/mailMail definitionsWriting Mail
server/notificationsNotificationsWriting Notifications
server/broadcastEvents pushed to the browserEvents and Channels
server/channelsWho may listen on each channelEvents and Channels
server/realtimeRealtime queries and mutationsRealtime Queries

You can group files in subfolders, for example server/jobs/reports/send-digest.ts.

You can also add folders of your own, such as server/lib, for shared helpers. Holo ignores folders it doesn't know about.

The storage folder ​

storage/ holds runtime data:

  • storage/database.sqlite when you use SQLite
  • storage/app/ and storage/app/public/ for files on the local and public disks
  • storage/framework/ for file-based sessions and rate-limit counters

storage/ is in .gitignore. Don't commit it.

Framework files ​

Holo adds its folders next to your framework's normal layout.

text
app/
├── layout.tsx
├── page.tsx
└── api/              # Route handlers
next.config.ts        # Wrapped with withHolo()
proxy.ts              # CSRF and route protection (with auth or security)
text
app/
└── app.vue           # Pages, layouts, middleware go under app/
server/
├── api/              # Nitro event handlers
└── middleware/       # Server middleware, such as CSRF
shared/
nuxt.config.ts        # Lists the @holo-js/adapter-nuxt module
text
src/
├── app.html
├── hooks.ts
├── hooks.server.ts   # Your server hooks
└── routes/           # Pages, +server.ts endpoints, load functions
vite.config.ts        # sveltekit(withHoloSvelteKit(...))

In Nuxt, server/ is shared: Nitro's server/api and server/middleware sit next to Holo's server/models, server/jobs, and so on. Each framework guide explains the details: Next.js, Nuxt, SvelteKit.

Auto-discovery ​

Holo scans these folders and records what it finds in .holo-js/generated/:

  • models, migrations, and seeders
  • commands, jobs, events, and listeners
  • broadcast events and channels
  • policies and abilities

This is how npx holo migrate knows your migrations, how a queue worker finds a job by name, and how holo list shows your custom commands.

Discovery runs automatically:

  • holo dev scans on start and watches for changes while it runs.
  • holo build scans before building.
  • npx holo prepare scans once without starting anything. The project's prepare script also runs it when your package manager installs dependencies.

If an editor shows stale types after you add a model or migration, run npx holo prepare.

Changing folder locations ​

The folder paths are set in config/app.ts under paths. Change a value to move that folder:

ts
import { defineAppConfig, env } from '@holo-js/config'

export default defineAppConfig({
  name: env('APP_NAME', 'my-app'),
  paths: {
    models: 'server/models',
    migrations: 'server/db/migrations',
    seeders: 'server/db/seeders',
    commands: 'server/commands',
    jobs: 'server/jobs',
    events: 'server/events',
    listeners: 'server/listeners',
  },
})

The keys you can set are models, migrations, seeders, factories, observers, commands, jobs, events, listeners, authorizationPolicies, authorizationAbilities, and generatedSchema. Any key you leave out uses the default shown in the tree above.

Next steps ​

Released under the MIT License.