# [OnStart] — work the app does when it is loaded

> `[OnStart]` marks a function the platform runs, as the app, whenever the app version is loaded — on every node that serves it, after every compile and deploy, and once at the start of an `osy test` run. It is where a kit starts its recurring work and makes its default rows, instead of checking for them inside every request. It runs again and again, so it must be idempotent: look first, then make. A hook that fails is reported, naming its package, and the app keeps serving; `Required = true` makes its failure stop the load instead.

<!-- id: function-on-start · area: function · stability: preview · html: https://osysharp.com/reference/function/on-start/ -->

## Summary        {#summary}
Some work belongs to the app being THERE rather than to anything happening in it: start the hourly clock, make the one
settings row a kit reads, check that the app's configuration makes sense. Mark a function `[OnStart]` and the platform
runs it whenever the app version is loaded:

```osy syntax
[OnStart]
void StartTheClock() {
  if (!ClockRow.Any()) { new ClockRow(); }      // look first — this runs on every load, on every node
}
```

Without it, that work hides inside ordinary requests — "is the clock running yet?" asked on every event, a default row
made by whoever happens to need it first — and every request pays for a question whose answer never changes.

## Signature      {#signature}
```osy syntax
[OnStart]
void <Name>() { … }                 // top-level; takes nothing; answers nothing

[OnStart(Required = true)]
void <Name>() { … }                 // the app cannot serve without it: a failure stops the load
```

## Description    {#description}

### When does it run?   {#when}
Whenever the app version is **loaded**:

- on each node, the first time that node serves the version — so after the node starts, and after every compile or
  deploy that makes a new version;
- again whenever a node loads the version anew (it unloaded an idle app and a request brought it back);
- at the start of an `osy test` run, once, before any fixture — so every fixture and test begins from a world the hooks
  have already made, as a served app does.

Hooks run in package order — a kit before the kits that use it, the app's own last — and each in a unit of work of its
own, committed before the next starts.

### Why it must be idempotent   {#idempotent}
Because it runs many times: once per load, per node — and two nodes may run it at the same moment. A hook that MAKES
something must look first, so the second run does nothing:

```osy syntax
[OnStart]
void EnsureTheSettings() {
  if (!Setting.Any()) { new Setting { Theme = "light" }; }
}
```

`osy lint` flags a hook that makes a row with no `if` around it (`correctness-start-hook-not-idempotent`):

```text
the start hook 'Seed' makes a new Setting every time it runs — and it runs whenever the app is loaded: on every node, after every compile and deploy, and again whenever a node reloads it.
```

### Who does it run as?   {#authority}
As the app — with the authority an event handler has, not any person's. So it may make a row nobody is granted to
create (the clock's one row, a kit's defaults), and what a package may not write it still may not.

### What if it fails?   {#failure}
The failure is **reported** — logged naming the hook, its package and the app — its writes are discarded, the other
hooks still run, and **the app keeps serving**. A start hook is housekeeping the app can live without for a while, and
the next load runs it again; refusing every request because a clock could not start would turn a small fault into an
outage.

When the app genuinely cannot serve without it, say so — `[OnStart(Required = true)]`. Then a failure stops the load:
no request is served by that version on that node, the failure names the hook, and the next request tries the load
again. In an `osy test` run a required hook that fails fails the run, naming itself.

### What may it be?   {#refusals}
A top-level function that takes nothing and answers nothing, and is not also an event handler, an `[Action]` or a test.
Anything else is refused where it is written, saying what would do:

```text
`[OnStart]` 'Takes' takes 1 parameter(s) — the platform calls a start hook with nothing to hand it. Read what it needs itself: `[OnStart] void EnsureTheDefaults() { if (!Setting.Any()) { new Setting(); } }`.
`[OnStart]` marks a top-level function the platform runs when the app is loaded — 'Holder.Method' is a method, and nothing holds an instance to call it on. Move it out of the class: `[OnStart] void EnsureTheDefaults() { if (!Setting.Any()) { new Setting(); } }`.
```

## Examples       {#examples}

### The row a kit needs, made once   {#example}
A setting nobody is granted to create — the hook makes it, as the app, the first time the app is loaded, and never again.

```osy title="a start hook that makes the one row the app reads" test app=function-on-start
entity HouseRules {
  [MaxLength(40)] string Greeting = "";
  security { allow read when IsAnonymous || IsAuthenticated; }
}

[OnStart]
void EnsureTheHouseRules() {
  if (!HouseRules.Any()) { new HouseRules { Greeting = "Welcome" }; }
}
```

```osy title="the row is there before anything else happened" run app=function-on-start
[Test]
void The_house_rules_are_there_from_the_start() {
  Assert.Equal(1, HouseRules.Count());
  Assert.Equal("Welcome", HouseRules.Single(h => true).Greeting);
}
```

## See also       {#see-also}
- [[On] — hear an event, after the commit that raised it](https://osysharp.com/reference/function/on/) — work done when something HAPPENS, rather than when the app is loaded
- [[Event] — what happens to a record, declared once](https://osysharp.com/reference/function/event/) — the events a kit hears
- [[Interest] — the events a handler of every event cares about](https://osysharp.com/reference/function/interest/) — what a handler of every event costs, and how to make it cost nothing
