Complete field-by-field reference for the App custom resource.
API Version:apps.nebari.dev/v1alpha1Kind:AppScope: Namespaced — the namespace must be labeled nebari.dev/managed=true.
Source:operator/api/v1alpha1/app_types.go
Content already present on a PersistentVolumeClaim.
The source is independent of the app kind: without runtime.pixiTask the content is
served statically by nginx; with it, the content is a pixi project run as a Python app.
Relative file paths → contents (nested paths like pkg/mod.py are supported). Materialized as a ConfigMap-backed volume. Keep under ~900KB total (ConfigMap limit). Paths must be relative and must not contain ...
Public https:// git repository URL. Rejected (API 422, operator Failed): any other scheme, embedded credentials (user:token@), a leading -, and cluster-internal or private hosts (IP literals in private/loopback/link-local ranges, localhost, single-label names, *.svc, *.cluster.local, *.internal, *.local). Private repositories are not supported yet.
ref
string
No
main
Branch or tag (cloned with git clone --branch, so a commit SHA does not work). Must not start with -.
subdir
string
No
repo root
Path within the repository containing the content root. Must not contain ...
The clone happens in a non-root init container at pod start; re-deploying picks up the
current state of the ref.
Name of an existing PersistentVolumeClaim in the app’s namespace. The claim must be labeled apps.nebari.dev/mountable=true (its owner’s opt-in); otherwise the App is Failed with Validated=False. Adding the label later re-validates the App.
CPU/memory requests and limits. Any cpu/memory request or limit left unset is filled from the cluster default for the app kind (static or Python); a filled limit never drops below the App’s own request. Init containers get the same bounds.
replicas
int
No
1
Desired replicas, 0–10. 0 stops the app (phase Stopped).
keepAlive
bool
No
false
Reserved for scale-to-zero idle reaping (not yet implemented).
pixiTask
string
No
—
When set, the app runs as a Python/pixi service: the operator copies the source into a writable workspace, runs pixi install (--locked when a pixi.lock is present), then pixi run <pixiTask>. The task must start a server on 0.0.0.0:8080 (PORT=8080 and HOME=/app are injected). Max 64 chars.
Keycloak groups intended to use the app. Passed to the NebariApp as auth.groups, but not enforced by the gateway in nebari-operator 0.1.0 — any signed-in realm user can open a private app.
users
[]string
No
Reserved. Not used by the operator or the gateway. The API rejects a non-empty list with 422; a value set with kubectl is stored and ignored. Tracked in #67.
subdomain
string
Yes
Lowercase DNS label, at most 63 characters. The app is served at https://<subdomain>.<appsDomain>. Unique across all Apps in the cluster: the API returns 409 for a taken subdomain, and if two Apps claim one anyway (e.g. via kubectl), the oldest keeps it and the other goes Failed with Validated=False, reason SubdomainTaken, and no NebariApp. Immutable after creation. The operator mirrors it into the apps.nebari.dev/subdomain label.
true registers the app as a tile on the Nebari landing page (name, description and thumbnail come from the spec); false hides it. Unset follows the cluster default — the chart’s apps.landingPage.enabled, which is false out of the box. The app is reachable at its URL and listed in the Apps UI regardless.