> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stellarium.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Structs: shared types across the network

> Declare structs on your nodes or in TypeScript, use them as types in contracts, events and resource functions, and let every peer check values against the same fields.

A Stellarium **struct** names a shape of object: the fields it has and the type of each. [Contracts](https://docs.stellarium.sh/concepts/contracts.md), [event types](https://docs.stellarium.sh/concepts/events.md) and resource functions use structs as types, so a value is checked against its fields wherever it is passed, returned, assigned or emitted, instead of being an unchecked `object`. Structs need RequestScript 1.7.0. See [Structs](https://docs.requestscript.org/language/structs) in the RequestScript docs for the language rules.

* **Your organization owns its structs.** You declare a struct on one of your nodes, in RequestScript or in TypeScript, and its path belongs to your organization.
* **Anyone uses them.** Any script on a node that knows a struct may use it as a type. Nodes learn structs from their peers.
* **Versions never change.** Every declaration and every reference names a version, and a version is never changed or deleted, so a reference always means the same fields on every node.

## Declaring a struct

A struct declares its fields and its version, and has no body:

```kotlin Address.req theme={null}
struct com.example.Address@1(street: string, city: string, postcode: string)
```

```kotlin Customer.req theme={null}
struct com.example.Customer@2(name: string, addresses: []com.example.Address@1, credit: decimal)
```

Send it to [`POST /v1/structs`](https://docs.stellarium.sh/node/http-api#structs) on a node of your organization, with the node's `API_KEY` or a run token from one of your organization's [API clients](https://docs.stellarium.sh/concepts/api-clients.md) for that node:

```bash theme={null}
curl -X POST https://node.example.com/v1/structs \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"source": "struct com.example.Address@1(street: string, city: string, postcode: string)"}'
```

```json Response theme={null}
{
  "path": "com.example",
  "name": "Address",
  "version": "1",
  "fields": [{ "name": "street", "type": "string" }, { "name": "city", "type": "string" }, { "name": "postcode", "type": "string" }],
  "ownerOrganizationId": "org_..."
}
```

* **The node's organization owns it.** A run token from another organization is refused with `403`.
* **The first organization keeps the path.** Once your organization declares `com.example.Address`, only your nodes may declare versions of it. Another organization is refused with `409`.
* **Versions are immutable.** Declaring the same version again with the same fields succeeds with `200` and changes nothing. With different fields it is refused with `409`. To change a shape, declare a new version.
* **Versions are never deleted.** Contracts and event types on other nodes may name any version, so there is no route to delete one.
* **Everything it names must be known.** A struct that names a struct the node doesn't know, contains itself, or nests more than 8 structs deep is refused with `400`.
* **Peers learn about it right away.** The node announces its structs to its peers whenever it declares a new one.

## Using structs

A struct type is the struct's name and version. Use it wherever a type goes:

```kotlin Ship.req theme={null}
contract com.example.Ship(customer: com.example.Customer@2): com.example.Address@1 {
    var home: com.example.Address@1 = { street: "1 Main St", city: "Springfield", postcode: "12345" }
    return customer.addresses[0]
}
```

* **Contracts and requests:** parameters, return types, `var` annotations and [state variables](https://docs.stellarium.sh/concepts/contracts.md#keeping-state-between-calls).
* **Event types:** `event com.example.OrderShipped(to: com.example.Address@1)`.
* **Resource functions:** parameter and return types, declared in TypeScript.

A value is checked structurally and leniently. Each declared field is converted to its type, a missing field is `null`, and fields the struct doesn't declare are kept. Any object with fitting fields fits, whatever struct it was built as. A value that doesn't fit fails the script, and `POST /v1/run` answers `422` with `"error": "Script failed"` and the field in `details`.

A reference always names its version, and never moves to a later one. To use a new shape, deploy a new version of the contract or event type that names it.

## Declaring structs in TypeScript

A resource function names structs in its types. Define them with `defineStruct`, and register them with the node:

```ts server.ts theme={null}
import { defineStruct, StellariumNode, type StellariumResource } from "stellarium-ts";

const Forecast = defineStruct("com.example.Forecast", 1, {
  city: "string",
  highs: "[]decimal",
});

const weather: StellariumResource = {
  id: 1,
  baseUrl: process.env.BASE_URL!,
  metadata: {},
  path: "com.example",
  name: "Weather",
  functions: [{
    name: "forecast",
    parameters: [{ name: "city", type: "string" }],
    returnType: Forecast.type, // "com.example.Forecast@1"
    exec: async (args) => ({ city: String(args[0]?.value), highs: [21.5, 23] }),
  }],
};

const node = new StellariumNode();
await node.registerStruct(Forecast);
await node.register(weather);
```

* **Field types are RequestScript type strings.** A field that is another struct names its version, by its `.type` or as `"com.example.Address@1"`. You can also pass structs to `start` as `structs: [Forecast]`.
* **The node needs an operator.** A node with structs needs `OPERATOR_URL`, and waits for its session before it serves, as a node with paid functions does: the session tells it its organization. It then declares each struct as its organization's, in any order.
* **Conflicts stop the node.** A path another organization owns, a version declared before with different fields, or a field naming a struct the node doesn't know stops the node from starting. So does a function type that names a struct without a version.
* **Parameters are checked before the call.** When a peer calls the function, the node checks its struct-typed parameters before anything is paid or run, and answers `400` if one doesn't fit. Parameters of other types reach `exec` as they come.
* **Return values are checked by the caller.** A return value that doesn't fit its struct fails the caller's script.

## How structs reach your peers

1. **Nodes announce their structs.** Each node tells its peers which structs its organization owns, signed with its key and carrying its [membership token](https://docs.stellarium.sh/concepts/events.md#membership-tokens). It announces again whenever it declares one. A node joining the network asks each peer for its structs, before their event types and resources, which may name them.
2. **Peers check the owner.** A peer learns a struct only if the membership token says the announcing node belongs to the struct's owner. It refuses a path another organization owns, and a version it already knows with other fields.
3. **Learned structs stay.** A struct a node learned stays known after the peer stops announcing it, since a version never goes away.

A node knows only the structs of its peers' organizations. A struct may name another organization's struct, and a node can use it once it has learned both from their owners.

## Unknown structs

* **Deploys:** a contract, event type or struct that names a struct the node doesn't know is refused with `400`.
* **Runs:** a script that names an unknown struct fails before it runs anything.
* **Peers' resources:** a node still learns a peer's resource when one of its functions names a struct it doesn't know. A script calling that function fails before any payment or network call. The resource's other functions still work.
* **Peers' event types:** a node doesn't learn an event type whose fields name a struct it doesn't know. It learns it from the peer's next event announcement, once it knows the struct.

## Limits

* A struct has at most 64 fields.
* Structs nest at most 8 deep, counting lists of structs.
* A struct's source is at most 16 KiB.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.