# project layout

> The shape of an Osy# project — a manifest at the root, and folders for model, seed, migrations and tests. What you put where decides what gets deployed and what only ever runs.

<!-- id: project-layout · area: project · stability: stable · html: https://osysharp.com/reference/project/layout/ -->

## Summary        {#summary}
An Osy# project is a manifest and four folders. The folders are not a style preference — they decide what is deployed
and what merely runs, so putting a file in the wrong one has consequences.

## Signature      {#signature}
```console
app.osy          the manifest — what compiles, what is tested, which capabilities the app uses
model/           entities, functions, security, UI       (compiled and deployed)
seed/            data the app needs in order to exist    (compiled and deployed)
migrations/      explicit schema and data migrations     (passed to a deploy, not compiled)
tests/           [Test] functions                        (run, never deployed)
```

## Description    {#description}

### Why the split matters   {#why}
`model/` and `tests/` are the two you will use every day, and the line between them is the one that matters: **tests
are never deployed.** A `[Test]` function lives in `tests/`, runs against a throwaway clone of the app, and never
reaches production — so a test may create rows, break rules and assert on the wreckage without any of it mattering.

Anything in `model/` **is** the application. If you put a test helper there, you have shipped it.

### Splitting model/ up   {#splitting-model}
`model/` is a glob, so its internal shape is yours. One file per area reads well and keeps a diff small:

```console
model/
  orders.osy        entities + the functions that act on them
  customers.osy
  security.osy      the security rules, in one place you can review
  ui/               components and pages
```

There is no required file naming and no ordering rule — the compiler reads the whole model as one unit, so a function
in one file may freely reference an entity declared in another.

### Seed vs migrations   {#seed-vs-migrations}
They are easy to confuse and they answer different questions.

- **`seed/`** — data the app cannot exist without: the roles, the statuses, the country list. It is re-applied to
  make the app *be what it says it is*, so it must be safe to run repeatedly.
- **`migrations/`** — a one-time, explicit change to an existing deployment: a column that needs backfilling, a
  non-additive schema change you have reviewed and authorised, or where a workflow run parked in a state you changed
  now stands.

If you find yourself wanting to "just seed" a production fix, you want a migration.

A `*.migration` is **not compiled with your model**, and it could not be: it is written against one PAIR of
versions and applied once, so re-applying it on every compile is exactly what must not happen. You hand it to the
deploy that needs it — `osy compile --migration migrations/<name>.migration` — and
`osy compile --generate-migration` writes it here for you to review first.

## See also       {#see-also}
- [app.osy](https://osysharp.com/reference/project/manifest/) — the `app.osy` that names these folders
- [Compiling your app](https://osysharp.com/reference/local/compiling-your-app/) — `osy compile`, which compiles model/ and seed/, and takes a migration with `--migration`
- [Running tests locally](https://osysharp.com/reference/testing/running-tests-locally/) — running what is in `tests/`
