DEV Community

Alex Spinov
Alex Spinov

Posted on

Pulumi Has Free Infrastructure as Code in Any Language — Here's Why Developers Love It

Terraform uses HCL. AWS CDK is verbose. Pulumi lets you write infrastructure in TypeScript, Python, Go, or C# — languages you already know.

Quick Start

curl -fsSL https://get.pulumi.com | sh
pulumi new aws-typescript
Enter fullscreen mode Exit fullscreen mode

Your First Infrastructure

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Create an S3 bucket
const bucket = new aws.s3.Bucket("my-bucket", {
  website: {
    indexDocument: "index.html",
  },
});

// Upload a file
const indexHtml = new aws.s3.BucketObject("index", {
  bucket: bucket.id,
  content: "<h1>Hello from Pulumi!</h1>",
  contentType: "text/html",
});

// Export the URL
export const url = pulumi.interpolate`http://${bucket.websiteEndpoint}`;
Enter fullscreen mode Exit fullscreen mode
pulumi up  # Preview and deploy
Enter fullscreen mode Exit fullscreen mode

Real-World: Full-Stack on AWS

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

// VPC with best practices
const vpc = new awsx.ec2.Vpc("app-vpc", { natGateways: { strategy: "Single" } });

// RDS Database
const db = new aws.rds.Instance("app-db", {
  engine: "postgres",
  instanceClass: "db.t4g.micro",
  allocatedStorage: 20,
  dbName: "appdb",
  username: "admin",
  password: config.requireSecret("dbPassword"),
  vpcSecurityGroupIds: [dbSg.id],
  dbSubnetGroupName: dbSubnetGroup.name,
  skipFinalSnapshot: true,
});

// ECS Fargate Service
const service = new awsx.ecs.FargateService("app", {
  cluster: cluster.arn,
  taskDefinitionArgs: {
    container: {
      name: "app",
      image: "my-app:latest",
      cpu: 256,
      memory: 512,
      portMappings: [{ containerPort: 3000 }],
      environment: [
        { name: "DATABASE_URL", value: pulumi.interpolate`postgres://admin:${dbPassword}@${db.endpoint}/appdb` },
      ],
    },
  },
});

// Application Load Balancer
const alb = new awsx.lb.ApplicationLoadBalancer("app-lb");
Enter fullscreen mode Exit fullscreen mode

Pulumi vs Terraform

Feature Pulumi Terraform
Language TS, Python, Go, C# HCL
Loops/Conditions Native count/for_each
Testing Unit tests Limited
IDE Support Full autocomplete HCL plugins
State Pulumi Cloud or S3 Terraform Cloud or S3
Reusable Code Functions/classes Modules
Learning Curve Low (if you know the language) Medium

Testing Infrastructure

import * as pulumi from "@pulumi/pulumi";
import { describe, it, expect } from "vitest";

describe("infrastructure", () => {
  it("bucket should have versioning", async () => {
    const bucket = new aws.s3.Bucket("test", {
      versioning: { enabled: true },
    });
    const versioning = await new Promise(resolve =>
      bucket.versioning.apply(v => resolve(v))
    );
    expect(versioning.enabled).toBe(true);
  });
});
Enter fullscreen mode Exit fullscreen mode

Secrets Management

# Set a secret (encrypted in state)
pulumi config set --secret dbPassword "super-secret-123"
Enter fullscreen mode Exit fullscreen mode
const config = new pulumi.Config();
const dbPassword = config.requireSecret("dbPassword");
// dbPassword is automatically encrypted in state
Enter fullscreen mode Exit fullscreen mode

Need cloud infrastructure for scraping? Check out my Apify actors — managed scraping infrastructure, no DevOps needed. For custom solutions, email spinov001@gmail.com.

Top comments (0)