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

# Typed resources

> Type every resource a Package emits against a pinned Kubernetes version and the CRDs it depends on

Every Package that `akua pkg init` scaffolds is typed against one Kubernetes version, and every CustomResourceDefinition you add as a dependency becomes a typed schema. A misspelled field, a wrong type, a value outside an enum or an API your Kubernetes version does not serve fails the render with the file and line, before anything reaches a cluster.

This guide assumes the `akua` CLI is installed (`brew install akua-dev/tap/akua`). Every command also works with the standalone `akuapkg` binary.

<Steps>
  <Step title="Scaffold a typed Package">
    `init` declares the Kubernetes 1.35 schemas in `akua.toml`, pins them by digest in `akua.lock`, and writes a `package.k` that uses them:

    ```bash theme={null}
    akua pkg init hello
    cd hello
    ```
  </Step>

  <Step title="Add a CRD dependency">
    `add` downloads the CRDs, pins their `sha256` and generates KCL schemas into `.akua/crds/`:

    ```bash theme={null}
    akua pkg add cert-manager --url https://github.com/cert-manager/cert-manager/releases/download/v1.16.0/cert-manager.crds.yaml
    ```

    The output names the modules to import, for example `import crds.cert_manager.cert_manager_io.v1 (Certificate, CertificateRequest, ClusterIssuer, Issuer)`.
  </Step>

  <Step title="Use the typed schemas">
    Replace `package.k` with a typed ConfigMap and a typed Certificate:

    ```python theme={null}
    import akua.ctx
    import k8s.api.core.v1 as corev1
    import crds.cert_manager.cert_manager_io.v1 as certmanager

    schema Input:
        appName: str
        replicas: int = 2
        host: str = "hello.example.com"

    input: Input = ctx.input()

    resources = [
        corev1.ConfigMap {
            metadata.name = input.appName
            data.replicas = str(input.replicas)
        }
        certmanager.Certificate {
            metadata.name = input.appName
            spec = {
                secretName = "${input.appName}-tls"
                dnsNames = [input.host]
                issuerRef = {name = "letsencrypt", kind = "ClusterIssuer"}
                privateKey.algorithm = "ECDSA"
            }
        }
    ]
    ```
  </Step>

  <Step title="Render">
    ```bash theme={null}
    akua pkg render --inputs inputs.example.yaml
    ```

    The render writes two manifests to `./deploy`. Commit `akua.toml`, `akua.lock` and `.akua/crds/`.
  </Step>
</Steps>

## What a mistake looks like

Change `"ECDSA"` to `"ECDSB"` and render again:

```text theme={null}
error[E2G22]: TypeError
---> File package.k:23:24: expected str(RSA) | str(ECDSA) | str(Ed25519), got str(ECDSB)
```

Misspelled fields fail with a suggestion (`Cannot add member 'secretname' to schema 'CertificateSpec', did you mean ...`), and a number where Kubernetes expects a string fails with `expected str, got int`. Every one of these exits with code 1 and error code [`E_RENDER_KCL`](/akua/errors/E_RENDER_KCL).

## Kubernetes versions

The default is the oldest Kubernetes minor version still supported upstream, 1.35, so what renders applies to every supported cluster.

| To | Run |
| - | - |
| Scaffold against another version | `akua pkg init my-app --k8s 1.33`, then `akua pkg lock` |
| Switch an existing Package | `akua pkg add k8s --k8s 1.36 --force` |
| Check the lock in CI | `akua pkg lock --check` |

A version switch type-checks the whole Package against the new release: an API it no longer serves, such as `flowcontrol.apiserver.k8s.io/v1beta3` from Kubernetes 1.32 on, fails the render.

## CRD sources

Any dependency source works, with `crds = true` for the whole source or a path inside it:

```bash theme={null}
# A release asset (implies crds = true)
akua pkg add cert-manager --url https://github.com/cert-manager/cert-manager/releases/download/v1.16.0/cert-manager.crds.yaml
# A git tag, narrowed to a directory
akua pkg add prometheus --git https://github.com/prometheus-operator/prometheus-operator --tag v0.80.0 --crds example/prometheus-operator-crd
# A Helm chart in an OCI registry
akua pkg add cnpg-crds --oci oci://ghcr.io/cloudnative-pg/charts/cloudnative-pg --version 0.22.1 --crds .
# A Helm chart in an HTTPS repository
akua pkg add jetstack --repo https://charts.jetstack.io --chart cert-manager --version v1.16.0 --crds templates
# A local directory
akua pkg add widgets --path ./widgets --crds .
```

Imports follow `crds.<dependency>.<group>.<version>`, with `-` and `.` turned into `_`. The generated `.akua/crds/` directory is committed; a render that finds it out of date with `akua.toml` or `akua.lock` fails with [`E_CRDS_STALE`](/akua/errors/E_CRDS_STALE) until you run `akua pkg lock`.

The conversion rules, naming details and known limits are in the upstream [typed resources guide](https://github.com/akua-dev/akua/blob/main/docs/typed-resources.md).

## Related topics

<CardGroup cols={2}>
  <Card title="Why typed and sandboxed" icon="circle-question" href="/akua/why">
    The problems with untyped templates and unsandboxed renderers.
  </Card>

  <Card title="Package format" icon="cube" href="/akua/package-format">
    The `Input` schema, `@ui` annotations and composition.
  </Card>

  <Card title="akua pkg add" icon="terminal" href="/akua/cli/add">
    Every flag of the command that adds dependencies.
  </Card>

  <Card title="Example: typed CRDs" icon="github" href="https://github.com/akua-dev/akua/tree/main/examples/16-typed-crds">
    A runnable Package with Kubernetes types and a CRD from a git tag.
  </Card>
</CardGroup>


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