Skip to content

Configuration & bindings

A Deployment or Job receives configuration in three ways. There is the env prop, there are variables Alchemy sets for you, and there are bindings. A binding is a capability an Effect program requests. It attaches environment variables at deploy time, and on some platforms it also attaches cloud permissions.

const api = yield* Kubernetes.Deployment("Api", {
cluster,
image: "ghcr.io/acme/api:v3",
port: 8080,
env: {
LOG_LEVEL: "info",
FEATURES: { search: true, beta: false },
BUCKET: bucket.bucketName,
},
});

Each key becomes a container environment variable:

  • Strings are passed as they are.
  • Other values are JSON-encoded. FEATURES above arrives as {"search":true,"beta":false}.
  • Outputs from other resources (bucket.bucketName) resolve at deploy time and make the workload depend on that resource.

A changed value re-applies the workload. A Deployment rolls its pods, and a one-shot Job runs again.

  • ALCHEMY_STACK_NAME is the Stack’s name.
  • ALCHEMY_STAGE is the stage being deployed.
  • ALCHEMY_PHASE is runtime.
  • PORT is the Deployment’s port. Only Deployments set it.

Variables from env override these, and these override variables from bindings.

Everything in env is written into the Deployment or Job object and into Alchemy’s state, where anyone who can read either can see it. For credentials, store the value in a Kubernetes Secret and have the workload read it from the cluster. A Secret is a Manifest with kind: "Secret":

const dbSecret = yield* Kubernetes.Manifest("DbSecret", {
cluster,
manifest: {
apiVersion: "v1",
kind: "Secret",
metadata: { name: "db", namespace: "apps" },
stringData: { url: databaseUrl },
},
});

Referencing a Secret from a container (envFrom, valueFrom, or a volume mount) is a container-level field. podTemplate can add the pod-level volumes entry, but not the container’s volumeMounts, because arrays in podTemplate replace the generated container list. When a workload needs Secret references, declare the whole Deployment as a Manifest.

A binding is a capability a workload’s Effect program asks for. It returns a typed client for the program to call, and registers what the workload needs at deploy time. Kubernetes workloads accept the same binding contract as a Lambda function or an ECS task:

  • env. Environment variables. Every cluster supports these.
  • Cloud grants. For example, AWS IAM policyStatements. These need a cluster whose platform issues cloud credentials to pods.

Bindings are declared inside the Effect implementation, so they apply to workloads built from main.

Inside an Effect program, yield a resource attribute to bind it. You get back an Effect that returns the value at runtime:

const worker = yield* Kubernetes.Job(
"Report",
{ cluster, main: import.meta.url },
Effect.gen(function* () {
const reportUrl = yield* api.url;
return {
run: Effect.gen(function* () {
const url = yield* reportUrl;
yield* Effect.log(`reporting to ${url}`);
}),
};
}),
);

Alchemy resolves api.url at deploy time, delivers it to the pod, and makes the Job depend on api. This works on every cluster, and it works for derived values too, such as an Output.interpolate string. Use the env prop for plain configuration, or for images that don’t run an Effect program.

Bindings to cloud services also grant permissions. One example is AWS.DynamoDB.PutItem(table). A cluster may have no way to issue cloud credentials to pods. On such a cluster, a deploy that uses one of these bindings fails with bindings carry cloud credential grants … but this cluster’s platform has no workload-identity adapter. You have two options:

  • Run the workload on a cluster whose platform issues credentials. On Amazon EKS, grants become an IAM role attached through EKS Pod Identity.
  • Give the program credentials yourself, through a Kubernetes Secret and your cloud SDK’s standard environment variables.
  • Jobs & CronJobs. Effect programs that read configuration and run to completion.
  • Bindings. How bindings work across Alchemy.