1---
2title: Configuration & bindings
3description: Pass configuration into Kubernetes workloads with env and Outputs, understand the variables Alchemy sets, keep secrets out of plain text, and use bindings.
4---
5
6A [Deployment](/kubernetes/workloads/deployments) or
7[Job](/kubernetes/workloads/jobs) receives configuration in three
8ways. There is the `env` prop, there are variables Alchemy sets for
9you, and there are **bindings**. A binding is a capability an Effect
10program requests. It attaches environment variables at deploy time,
11and on some platforms it also attaches cloud permissions.
12
13## Set environment variables
14
15```typescript
16const api = yield* Kubernetes.Deployment("Api", {
17 cluster,
18 image: "ghcr.io/acme/api:v3",
19 port: 8080,
20 env: {
21 LOG_LEVEL: "info",
22 FEATURES: { search: true, beta: false },
23 BUCKET: bucket.bucketName,
24 },
25});
26```
27
28Each key becomes a container environment variable:
29
30- Strings are passed as they are.
31- Other values are JSON-encoded. `FEATURES` above arrives as
32 `{"search":true,"beta":false}`.
33- Outputs from other resources (`bucket.bucketName`) resolve at
34 deploy time and make the workload depend on that resource.
35
36A changed value re-applies the workload. A Deployment rolls its pods,
37and a one-shot Job runs again.
38
39## Variables Alchemy sets
40
41- `ALCHEMY_STACK_NAME` is the Stack's name.
42- `ALCHEMY_STAGE` is the stage being deployed.
43- `ALCHEMY_PHASE` is `runtime`.
44- `PORT` is the Deployment's `port`. Only Deployments set it.
45
46Variables from `env` override these, and these override variables
47from bindings.
48
49## Keep secrets out of plain text
50
51Everything in `env` is written into the Deployment or Job object and
52into Alchemy's state, where anyone who can read either can see it.
53For credentials, store the value in a Kubernetes Secret and have the
54workload read it from the cluster. A Secret is a
55[Manifest](/kubernetes/objects/manifests) with `kind: "Secret"`:
56
57```typescript
58const dbSecret = yield* Kubernetes.Manifest("DbSecret", {
59 cluster,
60 manifest: {
61 apiVersion: "v1",
62 kind: "Secret",
63 metadata: { name: "db", namespace: "apps" },
64 stringData: { url: databaseUrl },
65 },
66});
67```
68
69Referencing a Secret from a container (`envFrom`, `valueFrom`, or a
70volume mount) is a container-level field. `podTemplate` can add the
71pod-level `volumes` entry, but not the container's `volumeMounts`,
72because arrays in `podTemplate` replace the generated container list.
73When a workload needs Secret references, declare the whole
74Deployment as a Manifest.
75
76## Bindings
77
78A binding is a capability a workload's Effect program asks for. It
79returns a typed client for the program to call, and registers what
80the workload needs at deploy time. Kubernetes workloads accept the
81same binding contract as a Lambda function or an ECS task:
82
83- **`env`.** Environment variables. Every cluster supports these.
84- **Cloud grants.** For example, AWS IAM `policyStatements`. These
85 need a cluster whose platform issues cloud credentials to pods.
86
87Bindings are declared inside the Effect implementation, so they
88apply to workloads built from `main`.
89
90### Bind values from other resources
91
92Inside an Effect program, yield a resource attribute to bind it. You
93get back an Effect that returns the value at runtime:
94
95```typescript
96const worker = yield* Kubernetes.Job(
97 "Report",
98 { cluster, main: import.meta.url },
99 Effect.gen(function* () {
100 const reportUrl = yield* api.url;
101 return {
102 run: Effect.gen(function* () {
103 const url = yield* reportUrl;
104 yield* Effect.log(`reporting to ${url}`);
105 }),
106 };
107 }),
108);
109```
110
111Alchemy resolves `api.url` at deploy time, delivers it to the pod,
112and makes the Job depend on `api`. This works on every cluster, and
113it works for derived values too, such as an `Output.interpolate`
114string. Use the `env` prop for plain configuration, or for images
115that don't run an Effect program.
116
117### Cloud credentials
118
119Bindings to cloud services also grant permissions. One example is
120`AWS.DynamoDB.PutItem(table)`. A cluster may have no way to issue
121cloud credentials to pods. On such a cluster, a deploy that uses one
122of these bindings fails with *bindings carry cloud credential grants
123… but this cluster's platform has no workload-identity adapter*. You
124have two options:
125
126- Run the workload on a cluster whose platform issues credentials.
127 On [Amazon EKS](/kubernetes/clusters/eks), grants become an IAM
128 role attached through EKS Pod Identity.
129- Give the program credentials yourself, through a Kubernetes Secret
130 and your cloud SDK's standard environment variables.
131
132## Where next
133
134- **[Jobs & CronJobs](/kubernetes/workloads/jobs).** Effect programs
135 that read configuration and run to completion.
136- **[Bindings](/infrastructure-as-effects/binding).** How bindings
137 work across Alchemy.