Choose compute
Each piece of code in a stack, called a workload, runs as a Worker, a Container, or a Daemon. Each workload uses one of them, and one stack can mix all three.
// Event-driven function that scales to zero
const processor = new alien.Worker("processor")
.code({ type: "source", src: "./processor", toolchain: { type: "typescript" } })
.permissions("processor")
.build()
// Long-running service with its own port
const ocr = new alien.Container("ocr")
.code({ type: "image", image: "ghcr.io/acme/ocr:2.4.0" })
.cpu(4)
.memory("16Gi")
.port(8080)
.permissions("ocr")
.build()
// One process on every machine in its pool
const collector = new alien.Daemon("collector")
.code({
type: "source",
src: "./collector",
toolchain: { type: "rust", binaryName: "collector" },
})
.permissions("collector")
.build()| AWS | Google Cloud | Azure | Kubernetes | |
|---|---|---|---|---|
Worker | Lambda | Cloud Run | Container Apps | Deployment |
Container | EC2 machines Alien manages | Compute Engine VMs Alien manages | Azure VMs Alien manages | Pods |
Daemon | One process per EC2 machine | One process per VM | One process per VM | DaemonSet |
Decision guide
| You need | Use |
|---|---|
| Code that reacts to uploads, queue messages, schedules, or commands, and scales to zero | Worker |
| A service that stays up: an API server, a database, a model server, anything with its own port or state | Container |
| One agent per host: log or metrics collection, a sandbox runtime, anything that needs the host's filesystem or network | Daemon |
Start with a Worker. Move to a Container when the work outlives a request, needs a GPU, or ships as an image you don't build with Alien. Use a Daemon only when the code must run on every machine.
To run code you don't trust, such as a customer's script or code a model wrote, use a Sandbox. Your app creates isolated sandboxes at runtime and runs commands inside them.
Worker
A Worker runs your handler on the cloud's serverless runtime. It starts on demand, so it costs nothing while idle.
const processor = new alien.Worker("processor")
.code({ type: "source", src: "./processor", toolchain: { type: "typescript" } })
.memoryMb(1024)
.timeoutSeconds(120)
.trigger({ type: "storage", storage: documents.ref(), events: ["created"] })
.trigger({ type: "schedule", cron: "0 3 * * *" })
.link(documents)
.permissions("processor")
.build()This Worker indexes each new file in the documents bucket and runs a nightly job. Workers also receive commands and HTTP requests on a public endpoint. Defaults are 512 MB of memory and a 180 second timeout.
Tradeoffs:
- On AWS, Workers build for
linux-arm64(Graviton) by default. A vendor image built only for x86 needs a Container instead. - Each invocation is bounded by the timeout. Long jobs belong in a Container, or split across queue messages.
- Workers don't run on Machines (on-prem and bare-metal hosts). Use a Container or Daemon there.
Container
A Container is a long-running service with its own ports, replicas, and optional disk. Use it for an API server, a model server, or a database.
const ocr = new alien.Container("ocr")
.code({ type: "image", image: "ghcr.io/acme/ocr:2.4.0" })
.cpu(4)
.memory("16Gi")
.gpu({ type: "nvidia-t4", count: 1 })
.minReplicas(1)
.port(8080)
.link(documents)
.permissions("ocr")
.build()cpu and memory are required. Other options add autoscaling (.autoScale()), persistent volumes with backups (.persistentStorage()), health checks, and public HTTP or TCP endpoints. Code is a prebuilt image or a source folder with a docker, typescript, rust, or python toolchain.
Tradeoffs:
- On AWS, Google Cloud, and Azure, Containers run on virtual machines in the customer's account. Machines cost money while they run, unlike an idle Worker.
- GPUs (
.gpu({ type, count })) work on cloud machines that offer them. Machines (on-prem hosts) don't support GPUs today. - On Machines, Containers must be stateless.
Private images
A Container can run an image from your private registry, such as GitHub Container Registry, Amazon ECR, or Docker Hub. Customers never need credentials for your registry:
alien releaserunsdocker pull --platform linux/<arch>for each target, with the Docker login of the machine that runs the release.- The release copies the image into itself.
- Deployments pull it from your manager with their deployment token.
No registry credentials go into alien.ts, the templates, or the Helm values.
- Log in on the machine or CI job that runs
alien release. ECR login tokens expire after 12 hours, so log in in the same CI job. - The image must exist for every target architecture:
linux/arm64on AWS,linux/amd64on Google Cloud and Azure, both on Kubernetes and Machines. Publish a multi-architecture image if you need more than one. - Pin the image by digest (
ghcr.io/acme/api@sha256:...). Alien copies whatever the tag points to when the release runs. - If the pull fails, the release stops with
docker pull failed for image '...'and Docker's output. Nothing is published. alien release --registry-usernameand--registry-passwordset the registry the release is pushed to. They are not used to pull your image.
Only Containers get this copy. A Worker or Daemon with type: "image" keeps the reference as written, and the cloud must pull it without credentials. For a private base image, build the Worker or Daemon with the docker toolchain from a Dockerfile that starts FROM your image.
Daemon
A Daemon runs exactly one instance on each machine in its pool. Use it for host-level agents that read host files, watch the host network, or manage other processes on the host.
const collector = new alien.Daemon("collector")
.code({
type: "source",
src: "./collector",
toolchain: { type: "rust", binaryName: "collector" },
})
.runtime({ mounts: [{ source: "/var/log", target: "/host/var/log" }] })
.link(documents)
.permissions("collector")
.build().runtime() grants host access: mounts, host network mode, the host PID namespace, or privileged mode. Grant only what the agent needs; the customer's security team will read it.
A Daemon scales with the number of machines, not with traffic.
Compute pools
Containers and Daemons run on a ComputeCluster: a set of machine pools in the customer's account. Alien creates a default cluster when a stack has Containers. Declare one yourself to define pools, for example a GPU pool that scales to zero next to a small fixed pool:
const compute = new alien.ComputeCluster("compute")
.pool("gpu", {
requirements: { cpu: 8, memory: "32Gi", accelerators: [{ type: "nvidia-t4", count: 1 }] },
scale: { type: "autoscale", min: 0, max: 4 },
})
.pool("general", {
requirements: { cpu: 2, memory: "8Gi", architecture: "arm64" },
scale: { type: "fixed", machines: 2 },
})
.build()Place a workload with .cluster("compute").pool("gpu"). Pools state portable requirements. The exact instance type is a deployment setting, so each customer can pick sizes during initial setup.
A ComputeCluster is always frozen: the customer's admin creates it during initial setup, and Alien manages the machines inside it afterwards. On Kubernetes, pools describe placement on the cluster's existing nodes and create no machines.
Where each type runs
| AWS, Google Cloud, Azure | Kubernetes | Machines | alien dev | |
|---|---|---|---|---|
| Worker | Yes | Yes | No | Native process |
| Container | Yes | Yes | Stateless only | Docker |
| Daemon | Yes | Yes | Yes | Native process |
The full matrix for every resource type is in Platforms. Every builder option is on the resource pages: Worker, Container, Daemon, ComputeCluster.
Next
- Using resources: give compute access to storage, KV, and queues
- Frozen and live resources: who owns each resource after initial setup
- Networking and endpoints: expose a Worker or Container over HTTPS