1---
2title: Manifests
3description: Apply any single Kubernetes object with Kubernetes.Manifest, including Namespaces, ConfigMaps, Secrets, StatefulSets, Ingresses, CRDs and custom resources, and order objects with Output references.
4---
5
6[`Kubernetes.Manifest`](/providers/kubernetes/manifest) applies one
7Kubernetes object, written as a literal object in the same shape as
8its YAML. Use it for everything
9[`Deployment`](/kubernetes/workloads/deployments) and
10[`Job`](/kubernetes/workloads/jobs) don't model. That includes
11Namespaces, ConfigMaps, Secrets, StatefulSets, DaemonSets, Ingresses,
12RBAC, NetworkPolicies, and custom resources.
13
14```typescript
15const config = yield* Kubernetes.Manifest("AppConfig", {
16 cluster,
17 manifest: {
18 apiVersion: "v1",
19 kind: "ConfigMap",
20 metadata: { name: "app-config", namespace: "apps" },
21 data: { LOG_LEVEL: "info" },
22 },
23});
24```
25
26The object is applied with server-side apply, re-applied whenever
27the manifest changes, and deleted on destroy.
28
29## Required fields
30
31- `apiVersion` and `kind` are required, as in YAML.
32- `metadata.name` is required. Objects that rely on `generateName`
33 aren't supported, because Alchemy needs a fixed name to find the
34 object again.
35- `metadata.namespace` is required for namespaced kinds. A Manifest
36 doesn't default to `default`. Omit the namespace only for
37 cluster-scoped kinds such as `Namespace`, `ClusterRole`, or
38 `CustomResourceDefinition`.
39
40Every other field (`spec`, `data`, `stringData`, `type`, `rules`, …)
41is passed through untouched. The Kubernetes API server validates the
42object when it's applied, and a rejected object fails the deploy
43with the server's message.
44
45## Order objects with Outputs
46
47Each Manifest is its own resource, and resources deploy in parallel
48unless one references another. To create an ordering, reference the
49`name`, `namespace`, `kind`, `apiVersion`, or `uid` attribute of
50another Manifest:
51
52```typescript
53const ns = yield* Kubernetes.Manifest("Namespace", {
54 cluster,
55 manifest: { apiVersion: "v1", kind: "Namespace", metadata: { name: "apps" } },
56});
57
58const quota = yield* Kubernetes.Manifest("Quota", {
59 cluster,
60 manifest: {
61 apiVersion: "v1",
62 kind: "ResourceQuota",
63 metadata: { name: "apps-quota", namespace: ns.name },
64 spec: { hard: { pods: "50", "requests.cpu": "20" } },
65 },
66});
67```
68
69`ns.name` resolves to `"apps"`. It also tells Alchemy to create the
70Namespace before the ResourceQuota, and to delete the ResourceQuota
71before the Namespace on destroy.
72
73## Run a StatefulSet
74
75Sometimes you need full control of a workload's containers, such as
76probes, volume mounts, sidecars, or Secret references. In that case,
77write the workload as a Manifest:
78
79```typescript
80const redis = yield* Kubernetes.Manifest("Redis", {
81 cluster,
82 manifest: {
83 apiVersion: "apps/v1",
84 kind: "StatefulSet",
85 metadata: { name: "redis", namespace: ns.name },
86 spec: {
87 serviceName: "redis",
88 replicas: 1,
89 selector: { matchLabels: { app: "redis" } },
90 template: {
91 metadata: { labels: { app: "redis" } },
92 spec: {
93 containers: [
94 {
95 name: "redis",
96 image: "redis:7.4",
97 ports: [{ containerPort: 6379 }],
98 volumeMounts: [{ name: "data", mountPath: "/data" }],
99 },
100 ],
101 },
102 },
103 volumeClaimTemplates: [
104 {
105 metadata: { name: "data" },
106 spec: {
107 accessModes: ["ReadWriteOnce"],
108 resources: { requests: { storage: "1Gi" } },
109 },
110 },
111 ],
112 },
113 },
114});
115```
116
117A Manifest applies exactly one object. The StatefulSet's headless
118Service is a second Manifest.
119
120## Custom resources
121
122Kinds Alchemy doesn't know are looked up through the cluster's API
123discovery endpoint, so custom resources work without any
124registration. The CRD must be installed before the first custom
125resource is applied. When the CRD comes from the same Stack,
126reference one of its attributes from the custom resource. An
127annotation is a convenient place for it:
128
129```typescript
130const crd = yield* Kubernetes.Manifest("WidgetCrd", {
131 cluster,
132 manifest: {
133 apiVersion: "apiextensions.k8s.io/v1",
134 kind: "CustomResourceDefinition",
135 metadata: { name: "widgets.acme.io" },
136 spec: {
137 group: "acme.io",
138 scope: "Namespaced",
139 names: { plural: "widgets", singular: "widget", kind: "Widget" },
140 versions: [
141 {
142 name: "v1",
143 served: true,
144 storage: true,
145 schema: {
146 openAPIV3Schema: {
147 type: "object",
148 properties: {
149 spec: { type: "object", properties: { size: { type: "integer" } } },
150 },
151 },
152 },
153 },
154 ],
155 },
156 },
157});
158
159const widget = yield* Kubernetes.Manifest("Widget", {
160 cluster,
161 manifest: {
162 apiVersion: "acme.io/v1",
163 kind: "Widget",
164 metadata: {
165 name: "w",
166 namespace: "default",
167 annotations: { "acme.io/crd": crd.name },
168 },
169 spec: { size: 3 },
170 },
171});
172```
173
174The reference also orders destroy, so the Widget is deleted before
175its CRD. CRDs installed by an operator's Helm chart come from a
176[HelmChart](/kubernetes/objects/helm-charts). Reference one of its
177attributes the same way.
178
179## Updates and replacement
180
181An object's identity is its cluster, `apiVersion`, `kind`, `name`,
182and `namespace`:
183
184- **Any other field.** Changing `spec`, `data`, or labels re-applies
185 the object in place.
186- **`apiVersion`, `kind`, `name`, or `namespace`.** Changing one
187 causes a replacement. The new object is applied, then the old one
188 is deleted.
189- **`cluster`.** Changing it causes a replacement. See
190 [Move a resource to another cluster](/kubernetes/clusters/connecting#move-a-resource-to-another-cluster).
191
192Server-side apply sends the full object and takes ownership of every
193field in it. Fields you remove from the manifest are removed from
194the object. Fields that Alchemy never set are left alone, whether
195controllers or other tools set them. See
196[How objects are managed](/kubernetes/workloads/object-lifecycle).
197
198## Attributes
199
200- `name` is the `metadata.name` of the object.
201- `namespace` is the `metadata.namespace`, or `undefined` for
202 cluster-scoped kinds.
203- `kind` is the object's kind.
204- `apiVersion` is the object's API version.
205- `uid` is the UID the API server assigned.
206- `ref` is a reference to the object (`apiVersion`, `kind`, `name`,
207 `namespace`).
208- `connection` is the cluster connection.
209
210## Where next
211
212- **[Helm charts](/kubernetes/objects/helm-charts).** Apply many
213 objects from a chart as one resource.
214- **[How objects are managed](/kubernetes/workloads/object-lifecycle).**
215 Field ownership, drift, and deletion.
216- **[`Manifest` reference](/providers/kubernetes/manifest).** Every
217 prop and attribute.