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

# Embedded types

> Model nested resource properties with plain classes or SubResources, and know when each is the right choice.

Some resource properties contain nested objects rather than simple values. There are two ways to model these in formae: **plain classes** and **SubResources**.

## Plain Classes vs SubResources

The choice depends on whether you need field-level hints on the nested object's properties.

### Plain Classes

Use plain classes for simple nested structures where you don't need `@FieldHint` annotations:

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
// Simple key-value structure - no FieldHints needed
open class Tag {
    hidden key: String
    hidden value: Any

    fixed Key: String = key
    fixed Value: Any = value
}
```

The `hidden`/`fixed` pattern handles output transformation (e.g., `key` becomes `Key`).

### SubResources

Use SubResources when you need `@FieldHint` on nested properties:

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
@formae.SubResourceHint
open class RootDirectory extends formae.SubResource {
    @formae.FieldHint {}
    path: String?

    @formae.FieldHint { createOnly = true }  // This requires SubResource!
    creationInfo: CreationInfo?
}
```

**The technical requirement:** formae's schema system only extracts `@FieldHint` annotations from properties if the containing class is a SubResource. FieldHints on plain class properties are ignored.

## When to Use Each

| Scenario                                                 | Use         |
| -------------------------------------------------------- | ----------- |
| Simple key-value pairs (tags, labels)                    | Plain class |
| No field-level hints needed                              | Plain class |
| Need `createOnly` on nested fields                       | SubResource |
| Need `updateMethod` / `indexField` on nested collections | SubResource |
| Complex nested configuration with multiple hint types    | SubResource |

## Defining a SubResource

SubResources extend `formae.SubResource` and use the `@SubResourceHint` annotation:

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
import "@formae/formae.pkl"

@formae.SubResourceHint
open class HealthCheck extends formae.SubResource {
    @formae.FieldHint {}
    path: String

    @formae.FieldHint {}
    intervalSeconds: Int

    @formae.FieldHint { createOnly = true }
    protocol: String
}
```

Then reference it in your Resource:

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
@formae.ResourceHint {
    type = "MyPlugin::Service::Server"
    identifier = "ServerId"
}
open class Server extends formae.Resource {
    @formae.FieldHint {}
    name: String

    @formae.FieldHint {}
    healthCheck: HealthCheck?
}
```

## Nested SubResources

SubResources can contain other SubResources for deeply nested structures:

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
@formae.SubResourceHint
open class CreationInfo extends formae.SubResource {
    @formae.FieldHint {}
    ownerUid: String

    @formae.FieldHint {}
    ownerGid: String

    @formae.FieldHint { createOnly = true }
    permissions: String
}

@formae.SubResourceHint
open class RootDirectory extends formae.SubResource {
    @formae.FieldHint {}
    path: String?

    @formae.FieldHint { createOnly = true }
    creationInfo: CreationInfo?
}
```

## Collections

For collections of nested objects, the approach depends on your needs:

**Plain class collection (no field hints):**

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
open class Tag {
    hidden key: String
    hidden value: Any
    fixed Key: String = key
    fixed Value: Any = value
}

@formae.ResourceHint { /* ... */ }
open class Instance extends formae.Resource {
    @formae.FieldHint {
        updateMethod = "EntitySet"
        indexField = "Key"
    }
    tags: Listing<Tag>?
}
```

**SubResource collection (with field hints):**

```kotlin theme={"languages":{"custom":["/languages/pkl.json"]}}
@formae.SubResourceHint
open class PolicyAttachment extends formae.SubResource {
    @formae.FieldHint {}
    policyArn: String

    @formae.FieldHint { createOnly = true }
    attachedAt: String?
}

@formae.ResourceHint { /* ... */ }
open class Role extends formae.Resource {
    @formae.FieldHint {
        updateMethod = "EntitySet"
        indexField = "PolicyArn"
    }
    policies: Listing<PolicyAttachment>?
}
```

See [Collection semantics](/plugin-development/concepts/collection-semantics) for details on `updateMethod` and `indexField`.

## Lifecycle

SubResources have no independent lifecycle:

* **Create**: Serialized as nested data within the parent's Properties
* **Read**: The plugin returns the full nested structure
* **Update**: Changes to SubResources trigger an update on the parent Resource
* **Delete**: Deleting the parent removes all nested data

## Summary

Start with plain classes for simple nested objects. Only use SubResource when you need `@FieldHint` annotations on nested properties. That's when the extra ceremony pays off.
