Skip to content

Pulsdev.io

TypeScript-native cloud infrastructure framework. Describe what you want - Puls discovers live state, diffs, and acts.

No state files. No plan step. No YAML. Just TypeScript against real APIs, idempotent by default.

@Deploy({ proxmox: CONFIG.STAGING })
class GameInfra extends Stack {
  server = Proxmox.VM("example-vm")
    .image(OS.UBUNTU_24_04)
    .cores(4).memory(8192)
    .ip("1.1.1.1").vlan(VLAN.STAGING)
    .sshKey(KEYS)
    .provision(["config/default.yaml", "config/service.yaml"]);
}

How it works

The moment you declare a resource, Puls starts an API lookup in the background - eager discovery. By the time deploy() runs, it already knows the current state. It diffs, acts, and moves on.

Declare resource  →  Discovery fires immediately
                  →  You chain config (.cores(), .ip(), ...)
                  →  deploy() awaits discovery, diffs, acts

Running the same stack twice is always safe. Resources that already match are skipped without an API write.


Providers

Provider Resources
AWS Route53, ACM, CloudFront, S3, Lambda, API Gateway, ECS/Fargate, RDS, SQS
Proxmox VM (clone, cloud-init, provision, cluster-aware node selection, replace)
DigitalOcean Droplet, Domain, Firewall, Certificate, LoadBalancer
Firebase Hosting, Functions, Firestore (Indexes & Rules), Storage (Rules/CORS), Auth, Remote Config, App Check
Google Cloud Cloud Run, Cloud SQL, Secret Manager, Pub/Sub, Cloud DNS, IAM (Service Accounts & Bindings)
Cloudflare Zone, DNS Records, KV Namespaces, R2 Buckets, Workers
Microsoft Azure Resource Groups, Blob Storage, App Service, Virtual Machines

A bigger example

@Deploy({ region: REGION.US_EAST_1 })
class AppStack extends Stack {
  // Secrets
  secret = AWS.SecretsManager(SECRETS.DB_KEY)

  // Database
  db = AWS.RDS("app-db")
    .engine(DB.POSTGRES_16)
    .size(DB_SIZE.SMALL)
    .credentials(this.secret);

  // Container service - auto-creates cluster, IAM role, log group, security group
  api = AWS.Fargate("app-api")
    .image("my-org/app:latest")
    .cpu(512).memory(1024)
    .port(3000)
    .replicas(2)
    .env({ DATABASE_URL: "..." });

  // Serverless function
  resizer = AWS.Lambda("image-resizer")
    .code("./functions/resizer")
    .runtime(RUNTIME.NODEJS_20)
    .memory(512);

  // HTTP routing
  gateway = AWS.APIGateway("app-api-gw")
    .route("GET /resize", this.resizer);

  // Queue for async jobs
  jobs = AWS.SQS("resize-jobs")
    .retention(7)
    .dlq("resize-jobs-dlq", 3);
}

Visual Import & Resource Adoption

Puls is designed for adopting existing cloud environments. Running the command:

puls import

starts an ephemeral local web server and opens a visual migration dashboard. Puls scans your cloud environment, models your resource dependencies (such as VM firewalls, or DNS records routing to content delivery distributions), and generates clean, modular TypeScript stack files directly inside your repository.


Community

Have questions or want to contribute? Join the conversation on Gitter|Matrix: pulsdev.io (Join)


Install

npm install @puls-dev/core
cp .env.example .env  # fill in your credentials
npx puls deploy your-stack.ts

Requires Node 20+.