# minPlatform — the oldest platform an app runs on

> The oldest platform release your app may be built and run on, as the first line of app.osy. osy init writes it, osy compile and osy deploy say when it is missing or behind your CLI (and never edit the file), a CLI older than it refuses the app, and a deploy into an environment on an older release is refused before anything is built.

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

## Summary        {#summary}
Your app is compiled by one platform: the release your `osy` is. `minPlatform` in `app.osy` says so, and three things
follow from it:

- a CLI **older** than it refuses the app (`osy validate`, `compile`, `launch`, `deploy`), naming both versions;
- `osy compile` and `osy deploy` **say so** in one line when it is missing or older than your CLI's release — with the
  exact line to write — and build for your CLI's release either way;
- `osy deploy` into an environment whose release is **older** is refused before anything is built or uploaded, and the
  platform refuses it again if it gets that far.

```osy title="the app says which platform it was written against" test app=project-min-platform
app Gallery {
  minPlatform "0.9.16";
  model "model/**/*.osy";
}

entity Poster {
  [Required, MaxLength(200)] string Title;
}
```

## Signature      {#signature}
```osy syntax
app <Name> {
  minPlatform "<MAJOR.MINOR.PATCH>";   // a platform release, like "0.9.16"
  …
}
```

The value is a release number — three numbers, nothing else. It is written once; a second line is refused.

## Description    {#description}

### Who writes it   {#who-writes-it}
`osy init` writes it as the first line of the new app's `app { }` block. After that it is yours: no verb that compiles
or checks the app edits `app.osy`.

| verb | an app with no `minPlatform` | an older one than your CLI | a newer one than your CLI |
|---|---|---|---|
| `osy init` | writes your CLI's release | — | — |
| `osy compile`, `osy launch`, `osy deploy` | notes the line to write | notes the line to write | **refused** |
| `osy validate`, `osy check` | leaves it alone | notes the line to write | **refused** |

A compile never edits the source it compiles, so the note is the whole of it:

```text
· app.osy says `minPlatform "0.9.4"`, and this CLI compiles against 0.9.16, so what it builds needs 0.9.16 — write
  `minPlatform "0.9.16";` in its `app { }` block to say so.
```

What you deploy is safe either way: `osy deploy` sends the release it built your app at — your CLI's — with the
deploy, so an app this CLI built is never built on an older release, whatever the file says. Raising the line keeps
the file honest: your app was compiled by your CLI's platform and by no older one, so a floor below that is a claim
nothing checked.

### When your CLI is older than the app   {#cli-too-old}
Someone wrote the app with a newer `osy`. What your CLI would say about it proves nothing about the platform it needs,
so it stops:

```text
✗ Shelf needs platform 0.9.20 or newer (app.osy says `minPlatform "0.9.20"`), and this CLI compiles against
  0.9.16 (0.9.16): update the CLI — `osy upgrade` — and run this again. Nothing was compiled.
```

`osy --version` prints the release your CLI is.

### When the environment runs an older release   {#deploy}
An environment runs your app on one platform release, and its zone builds every deploy on that release. `osy deploy`
asks where the app runs before it builds anything; when the environment's release is older than `minPlatform`:

```text
✗ shelf needs platform 0.9.16 or newer (its app.osy says `minPlatform "0.9.16"`), and prod runs it on release 0.9.4
  — nothing was built or sent. Move shelf in prod to release 0.9.16 or later from its Platform page, or wait for
  0.9.16 to be GA.
```

The deploy carries `minPlatform` to the platform, which refuses the same way before it records a version or starts a
build. That is also the only check for an environment's **first** deploy, whose release the platform chooses then:
the newest release your organization can run. If that is older, the refusal says to wait for the release to be GA.

### An unreleased CLI   {#unreleased}
A CLI built from source is not any release. It knows the newest release it contains: built exactly at that release it
counts as it, and built after it — the usual case — it counts as the **next** release, because it may compile
anything added since. `osy --version` shows which (`unreleased, 3 commit(s) after 0.9.15`), and an app it compiles
needs that next release (and `osy init` writes it). Such an app deploys once that release exists. A build that knows no
release at all checks and writes nothing.

### Kits state theirs too   {#kits}
A kit's `package.osy` carries the same `minPlatform` line, with the same meaning: a floor. The platform refuses a kit
on an older release, and takes it on any newer one — however much newer — where compiling it in your project is the
verdict on whether it still runs ([package.osy](https://osysharp.com/reference/project/package/)). A kit's floor must cover what it uses: a kit naming a built-in icon or a baseline
enum member that arrived in a later release needs that release as its floor.

## See also       {#see-also}
- [app.osy](https://osysharp.com/reference/project/manifest/) — everything else `app.osy` says
- [package.osy](https://osysharp.com/reference/project/package/) — a kit's `minPlatform` and the releases it runs on
- [Hosting an Osy# app](https://osysharp.com/reference/project/hosting/) — environments, and the release each runs
- [Deploying while workflows are running](https://osysharp.com/reference/project/app-versions/) — the versions a deploy records
