Docs

Stacks

A stack is the complete set of infrastructure Alien provisions in each customer's environment. You define it in alien.ts — Alien translates each resource to the native cloud service at deploy time (S3 on AWS, Cloud Storage on GCP, Blob Storage on Azure, and so on).

Defining Resources

Each resource type maps to a native cloud service on every platform.

Functions

Serverless compute. Deploys as Lambda on AWS, Cloud Run on GCP, Container Apps on Azure. Point at a source directory with a toolchain — Alien compiles and packages for the target platform.

import * as alien from "@alienplatform/core"

const api = new alien.Function("api")
  .code({ type: "source", src: "./api", toolchain: { type: "typescript" } })
  .ingress("public")
  .permissions("execution")
  .build()

See Function reference for configuration options, Events & Triggers for queue, storage, and cron triggers, and Environment Variables for runtime configuration.

Storage

Object storage — S3 on AWS, Cloud Storage on GCP, Blob Storage on Azure.

const data = new alien.Storage("data")
  .publicRead(false)
  .versioning(false)
  .build()

See Storage reference for configuration options and behavior.

KV

Key-value store — DynamoDB on AWS, Firestore on GCP, Table Storage on Azure.

const cache = new alien.Kv("cache").build()

See KV reference for behavior and limits.

Queue

Message queue — SQS on AWS, Pub/Sub on GCP, Service Bus on Azure.

const tasks = new alien.Queue("tasks").build()

See Queue reference for behavior and limits.

Vault

Secret storage — SSM Parameter Store on AWS, Secret Manager on GCP, Key Vault on Azure.

const secrets = new alien.Vault("credentials").build()

See Vault reference for behavior and limits.

Artifact Registry

Container image registry — ECR on AWS, Artifact Registry on GCP, ACR on Azure.

const images = new alien.ArtifactRegistry("images").build()

See Artifact Registry reference for configuration options.

The Stack Object

A Stack groups your resources and declares whether each one is frozen or live:

export default new alien.Stack("my-app")
  .add(data, "frozen")     // monitor only
  .add(cache, "frozen")    // monitor only
  .add(tasks, "frozen")    // monitor only
  .add(api, "live")        // manage remotely
  .build()

Frozen vs. Live

Every resource you add to a stack is either frozen or live. This is a tradeoff between security and control:

  • 🧊 Frozen — Alien can only monitor it. Created once during initial setup, then Alien has no permissions to modify or delete it. Good for stable infrastructure — a storage bucket, a queue, a VPC.
  • 🔁 Live — Alien can manage it from your cloud. You can push code updates, roll config changes, and redeploy without the customer's involvement. Good for anything you need to control remotely — like a function running your business logic.

During initial setup, all resources are created together. After that, Alien can only manage live resources — frozen resources are skipped entirely. Alien auto-derives the management permissions from the frozen/live choice, so the customer's security team can audit exactly what your software is allowed to change.

See Frozen & Live for the full two-phase deployment model.

Permission Profiles

Permission profiles control what your application code can access at runtime. They're separate from the management permissions Alien uses to deploy — those are auto-derived.

A profile is a named set of permissions that maps resource names to permission sets. Functions reference a profile by name with .permissions("profile-name"):

const api = new alien.Function("api")
  .permissions("execution")  // use the "execution" profile
  .build()

You define profiles in the stack's .permissions() block. Each key inside a profile is either a specific resource name or "*" (all resources of that type):

export default new alien.Stack("my-app")
  .add(data, "frozen")
  .add(cache, "frozen")
  .add(tasks, "frozen")
  .add(api, "live")
  .permissions({
    profiles: {
      execution: {
        data: ["storage/data-read", "storage/data-write"],
        cache: ["kv/data-read", "kv/data-write"],
        tasks: ["queue/data-read", "queue/data-write"],
      },
    },
  })
  .build()

Under the hood, each profile becomes a cloud identity — an IAM Role on AWS, a Service Account on GCP, or a Managed Identity on Azure. The permission sets (storage/data-read, kv/data-write, etc.) are translated to the correct cloud-specific policies automatically.

See Permissions for the full reference on scopes, built-in permission sets, and custom permissions.

Linking Resources

Use .link() to connect a function to a resource. This injects the connection parameters as environment variables at runtime — your code can then access the resource using the Alien SDK or native cloud SDKs:

const api = new alien.Function("api")
  .link(data)
  .link(cache)
  .link(tasks)
  .build()

A function can only access resources it's linked to. This is enforced at the cloud level through permission profiles.

Examples

AI Agent with Remote Commands

An AI worker that runs in the customer's cloud, with storage for files and a vault for integration credentials. Remote commands let your control plane invoke tool calls without any inbound networking:

import * as alien from "@alienplatform/core"

const workspace = new alien.Storage("workspace").build()
const secrets = new alien.Vault("integrations").build()

const agent = new alien.Function("agent")
  .code({ type: "source", src: "./", toolchain: { type: "typescript" } })
  .link(workspace)
  .link(secrets)
  .commandsEnabled(true)
  .ingress("private")
  .permissions("execution")
  .build()

export default new alien.Stack("my-agent")
  .add(workspace, "frozen")
  .add(secrets, "frozen")
  .add(agent, "live")
  .permissions({
    profiles: {
      execution: {
        workspace: ["storage/data-read", "storage/data-write"],
        integrations: ["vault/data-read"],
      },
    },
  })
  .build()

Event-Driven Pipeline

A worker that processes messages from a queue, with storage for results:

import * as alien from "@alienplatform/core"

const results = new alien.Storage("results").build()
const jobs = new alien.Queue("jobs").build()

const worker = new alien.Function("worker")
  .code({ type: "source", src: "./worker", toolchain: { type: "typescript" } })
  .link(results)
  .link(jobs)
  .trigger({ type: "queue", queue: jobs.ref() })
  .permissions("processing")
  .build()

export default new alien.Stack("pipeline")
  .add(results, "frozen")
  .add(jobs, "frozen")
  .add(worker, "live")
  .permissions({
    profiles: {
      processing: {
        results: ["storage/data-read", "storage/data-write"],
        jobs: ["queue/data-read"],
      },
    },
  })
  .build()

Public API with Cache

A public-facing API with a KV cache and vault for API keys:

import * as alien from "@alienplatform/core"

const cache = new alien.Kv("cache").build()
const secrets = new alien.Vault("api-keys").build()

const api = new alien.Function("api")
  .code({ type: "source", src: "./api", toolchain: { type: "typescript" } })
  .link(cache)
  .link(secrets)
  .ingress("public")
  .memoryMb(512)
  .timeoutSeconds(30)
  .permissions("execution")
  .build()

export default new alien.Stack("my-api")
  .add(cache, "frozen")
  .add(secrets, "frozen")
  .add(api, "live")
  .permissions({
    profiles: {
      execution: {
        cache: ["kv/data-read", "kv/data-write"],
        "api-keys": ["vault/data-read"],
      },
    },
  })
  .build()

What's Next

On this page