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

# Namespaces

> Where installations land in Kubernetes, how Ryvn creates and labels namespaces, and what your charts must not do.

Every installation runs in one Kubernetes namespace. By default it's the environment's namespace. You can pick a different one, but Ryvn still creates it, labels it, and uses those labels to track what it deployed. Charts should never do this themselves.

## The default namespace

Each environment gets a namespace with the same name. Environment `prod-us` deploys into namespace `prod-us`. Environment names can't change, so the namespace can't either. If you want a friendlier name in the dashboard, set a display name.

Every service type, blueprint child, and preview uses this namespace unless you say otherwise. Previews sharing one namespace is why two previews can't reach each other by bare service name.

In templates, use `{{ .ryvn.env.defaultNamespace }}`. Blueprint templates can also use `{{ EnvironmentNamespace }}`.

```yaml theme={null}
config: |
  auth-tls-secret: '{{ .ryvn.env.defaultNamespace }}/{{ k8sSecretName "ca" }}'
```

<Tip>
  Leave `namespace` unset unless you need something else. The default namespace already exists, the agent already has permissions in it, and everything (secrets, outputs, pull credentials, health, JIT access) works there with no extra setup.
</Tip>

## Ryvn's own namespaces

Platform components live apart from your workloads:

| Namespace       | What's in it                                            |
| --------------- | ------------------------------------------------------- |
| `ryvn-system`   | The agent, its credentials, cluster access RBAC         |
| `observability` | Log and metric collectors, `kube-state-metrics`         |
| `kube-system`   | Add-ons like KEDA, next to the cluster's own components |

These are reserved. [JIT access](/docs/guides/jit-kubectl-access) can't target them and they never get application role bindings.

## Using a different namespace

Set `namespace` on the installation:

```yaml theme={null}
installations:
  - service: inngest
    namespace: inngest
```

The value must be a plain name. Templates like `{{ .ryvn.env.defaultNamespace }}` aren't expanded here. Omit the field if you want the default.

On install, the agent creates the namespace if it's missing and adds Ryvn's labels. If it already exists, the agent just adds the labels. You don't need to create it first.

The namespace can't change after install. YAML sync rejects the change:

```
namespace is immutable: cannot change from "prod-us" to "inngest". Delete and recreate the installation to change its namespace
```

To move an installation, uninstall and reinstall it. If that's not an option, contact Ryvn. The Helm release and Ryvn's record have to move together and there's no self-serve way to do it.

A few other things to know:

* Installation names must be unique across the whole environment, not just within a namespace.
* Same-namespace installations reach each other at `<installation>:<port>`. Across namespaces, use `<installation>.<namespace>.svc.cluster.local:<port>`.
* Importing an installation into another environment moves it to that environment's default namespace, unless it had an explicit namespace.

## Declaring namespaces on the environment

Use the environment's `namespaces` list when a namespace needs to exist before anything is installed into it, or when you want labels on it. Pod Security Admission is the usual reason:

```yaml theme={null}
kind: Environment
metadata:
  name: prod-us
spec:
  namespaces:
    - name: prod-us
      labels:
        pod-security.kubernetes.io/enforce: baseline
    - name: inngest
```

Ryvn creates each namespace with your labels plus its own, and reapplies them on every sync. The default namespace exists either way; list it only to put labels on it. Removing an entry doesn't delete the namespace. Ryvn never deletes namespaces, on sync or on uninstall.

## Labels

Ryvn finds its namespaces by label, not by name. The agent only watches labeled namespaces, and health reporting, secret distribution, pull credentials, and access bindings all follow that set.

| Label                                         | Where                                                                       |
| --------------------------------------------- | --------------------------------------------------------------------------- |
| `ryvn.app/env-name=<environment>`             | Every namespace Ryvn manages                                                |
| `ryvn.app/managed=`                           | Every application namespace Ryvn manages                                    |
| `ryvn.app/system-namespace=`                  | `ryvn-system` only                                                          |
| `ryvn.app/requires-registry-creds=<registry>` | Optional. Get pull credentials in a namespace Ryvn doesn't otherwise manage |

The agent adds these itself. If it isn't allowed to create or edit namespaces (a locked-down existing cluster), whoever runs the cluster needs to create the namespace with the first two labels before installing. Without them the install can succeed while the installation sits at Pending forever, because the agent can't see the pods.

A namespace with both labels gets, automatically:

* Pull credentials for the Ryvn registry.
* Variable group secrets for the installations in it, named `<installation>-<variable-group>`.
* `ryvn-outputs-<installation>` secrets carrying Terraform and blueprint outputs.
* The role bindings JIT access grants resolve against.

Don't put these labels on another environment's namespaces, and don't remove them from namespaces Ryvn deploys into.

## What charts must not do

A chart deployed by Ryvn must not create or pin its own namespace. Both break health reporting in the same way: the installation shows Pending with zero pods while everything is actually running.

Don't template `kind: Namespace`. Helm replaces the namespace object and wipes Ryvn's labels, so the agent loses track of it. If an upstream chart has a `namespace.create` value, set it to `false`. And don't use a chart just to create namespaces for other installations. Ryvn already creates any namespace a child names, so the chart is redundant, and because blueprint children install in no particular order it races the agent and fails with:

```
Namespace "operator-system" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata
```

If it does win the race, uninstalling it later deletes those namespaces and everything in them.

Don't hard-code `metadata.namespace` on resources. Use `{{ .Release.Namespace }}` or leave it out. Ryvn looks for workloads in the release namespace, so resources pinned elsewhere never resolve to running pods.

If a chart needs a specific namespace, set `namespace` on the installation. If that namespace needs labels, declare it in the environment's `namespaces` list.

## Namespaces you create yourself

If your workloads create namespaces on the fly, Ryvn can't see them until they're labeled:

```yaml theme={null}
metadata:
  labels:
    ryvn.app/env-name: prod-us
    ryvn.app/managed: ""
```

That asks for full management: secrets and pull credentials get distributed in, and reporting picks it up. If you only want pull credentials, use `ryvn.app/requires-registry-creds` alone.

Kubernetes secrets don't cross namespaces. A `secretKeyRef` can't read a secret Ryvn put somewhere else, so anything that needs Ryvn-managed secrets has to run in a managed namespace. Copying secrets into unmanaged namespaces is on you. A Kyverno clone policy keyed on `ryvn.app/installation-name` is what customers usually do.

## Scoped-down clusters

On clusters Ryvn provisions, the agent is cluster admin and all of the above just works. On an [existing cluster](/docs/provision/existing-cluster) with a narrower role, the agent needs to read workloads and write secrets in every namespace an installation targets, plus create or edit the namespace if you want Ryvn to make it.

Symptoms that mean a permissions gap, not a chart problem:

| Symptom                                                                                             | Cause                                                                        |
| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `Kubernetes namespace does not exist — create the namespace first`                                  | Agent can't create the namespace and nobody pre-created it                   |
| `failed to update secret: resource name may not be empty`                                           | Agent can't write secrets in that namespace                                  |
| `FailedToRetrieveImagePullSecret` on pods                                                           | Namespace isn't labeled, or agent can't write secrets there                  |
| Pending with healthy pods in `kubectl`                                                              | Namespace isn't labeled, or the chart pins its own namespace                 |
| `exists and cannot be imported into the current release: invalid ownership metadata` on a Namespace | The chart creates a namespace Ryvn already created. Remove it from the chart |

Fastest unblock: drop the `namespace` field and use the default. Split into separate namespaces once the RBAC for them exists.
