# execution side

> Where a function runs. Osy# infers it from the body: a function that reads data runs on the server, a function that touches the router or the theme runs in the browser, and a pure function runs wherever the caller already is.

<!-- id: function-execution-side · area: function · stability: stable · html: https://osysharp.com/reference/function/execution-side/ -->

## Summary        {#summary}

Where a function runs. Osy# infers it from the body: a function that reads data runs on the server, a function that
touches the router or the theme runs in the browser, and a pure function runs wherever the caller already is. You do
not write the side, and you do not wire the round trip — calling a function that runs elsewhere is an ordinary call.

## Signature      {#signature}

```osy syntax
Side = Server | Client | Either   // inferred — never spelled in source
```

## Description    {#description}

Every function, method and constructor has an **execution side**: the place its body runs. There are three.

| Side | Meaning |
|---|---|
| `Server` | The authority. Anything that reads the data store, checks security, or touches a secret. |
| `Client` | The browser. Anything that acts on something only the browser has — the router, the session, the theme. |
| `Either` | Pure work. It runs wherever the caller already is, and never forces a trip across the network. |

**You never declare the side.** The compiler reads the body and works it out, then works out every *caller's* side
from that, and so on up the call graph. The rule is simply: **a function is at most as client-side as the most
server-side thing it can reach.**

```osy title="the side travels up the call graph, not from the top line" syntax
string Greeting(string name) {           // Either — pure. Runs in the browser if that's where you called it.
  return "welcome " + name;
}

User CurrentUser(string email) {         // Server — it reads the data store.
  return Users.Single(u => u.Email == email);
}

string Welcome(string email) {           // Server — because it calls CurrentUser.
  return Greeting(CurrentUser(email).Name);
}
```

`Welcome` is `Server` even though its own body looks pure, because it *reaches* a data read. That is the whole point:
the side is a property of what a function can actually do, not of what its top line looks like.

### Why this matters   {#cross-side-calls}

Calling a function that runs on the other side is still just a call. You write `Login(email, password)` and the
platform does the rest: it evaluates the arguments where you are, suspends, runs the callee on the other side, and
resumes you with the result — including through a `try`/`catch`, which behaves exactly as it would locally.

What the side changes is the **cost**. A call to an `Either` function from a browser action runs *in the browser*, in
process, with no network at all. The same call to a `Server` function is a round trip. Because the side is inferred
rather than assumed, a helper that merely formats a string does not silently cost you a request.

### A body can mix sides   {#mixed-body}

A `Server` function may still do client-located work — show something, ask the user, navigate — and the platform hands
that piece back to the browser and picks up where it left off:

```osy title="one straight-line body that starts server and ends in the browser" syntax
[Page("/orders")]
component OrderPage() {
  action Cancel(Order order) {           // a browser action
    if (Confirm(order)) {                // ↩ runs on the server: it reads and validates…
      Navigation.Go("/orders");          //   …and this line comes back to the browser
    }
  }
}
```

A body with **both** a server anchor and a client anchor is `Server`: it starts on the authority and hands its
client-located parts back. That is not a compromise — it is how a flow can validate on the server and still ask the
user something in the browser, in one straight-line function.

### The standard library is pure, so it runs where you are   {#stdlib}

Calling `Text.Upper`, `Text.Trim`, `Text.Substring` or `string.Join` — and the instance spellings that lower onto
them, like `name.ToUpper()`, `s.Trim()` and `s.Length` — does **not** make a function `Server`. They are pure
operations on a value you already hold, so they run wherever the caller is:

```osy title="stdlib calls are pure, so they cost no round trip" syntax
string Initials(string first, string last) {          // Either — no round trip
  return first.Substring(0, 1) + last.Substring(0, 1);
}
```

The same goes for `name.Contains("x")`, `StartsWith` and `EndsWith`.

Some library calls **are** server-anchored, and for reasons worth stating: `Security.HashPassword` needs the host's
salt generator, `Security.IssueJwt` needs the host's signing key, and `Crypto.Encrypt` needs an encryption key the
browser must never hold. A function that calls one of those is `Server`, as it should be.

Where a library call cannot yet run in the browser, it simply runs on the server — the answer is the same, the call
just costs a round trip. Correctness never depends on which side a pure call lands on: both sides are held to the
same answers, character for character, down to how `Text.Upper` treats the German ß.

### The one thing that is not negotiable   {#queries-are-server}

A query over the **data store** is always `Server` — the data lives on the server, so reading it is a server
operation. An entity query pins its function to the server, always.

A query over a **local list** is not a data read, and does not:

```osy title="a query over a local list is not a data read" syntax
int Cheap(List<Line> lines) {                    // Either — runs in the browser
  return lines.Where(l => l.Price < 10).Count();
}
```

## Examples       {#examples}

```osy title="a pure helper runs in the browser" test app=side-inference
string Initials(string first, string last) {
  return first.Substring(0, 1) + last.Substring(0, 1);
}
```

```osy title="reading data pins a function to the server" test app=side-inference
entity Customer { string Email; string Name; }

string NameFor(string email) {
  return Customer.Single(c => c.Email == email).Name;
}
```

### Pinning it — `[Client]` and `[Server]`   {#pinning}
Side is INFERRED from the body, and that is the normal case. `[Client]` and `[Server]` are an ASSERTION on top of
that inference, and they PIN the answer:

```osy title="an assertion, not a hint — the compiler checks it" syntax
[Client] string Initials(string name) { … }   // must stay client-runnable
[Server] decimal Rate() { … }                 // must stay on the server
```

Two things they buy. **A helper that quietly stops being client-runnable** — someone adds a data read three calls
down — turns into a silent network round trip today, and nothing tells you; pinned, it is a compile error. And they
**resolve ambiguity** for a body whose behaviour depends on which engine runs it: .NET and JS regular expressions
are different dialects, so the same pattern can match differently depending on where the cursor happens to be. There
an `Either` body is the hazard, and a pin in either direction removes it.

⚠ Marking a function both is refused — it runs in one place or the other.

## See also       {#see-also}
- [function](https://osysharp.com/reference/function/declaration/) — declaring a function
- [LINQ over a local list](https://osysharp.com/reference/query/in-memory-linq/) — LINQ over a local list, which stays client-runnable
- [component](https://osysharp.com/reference/ui/component/) — a component, whose actions always begin in the browser
