Cloud Infrastructure Automation

Migrating to Pulumi from Terraform

HashiCorp Terraform provides a custom DSL called Hashicorp Configuration Language (HCL) to describe and provision infrastructure resources on Terraform providers.

Pulumi enables you to describe the same infrastructure resources as real code, providing huge productivity gains, and has deep support for cloud native technologies such as Kubernetes and serverless programming.

Need help converting your Terraform templates into Pulumi code? Drop us a line.

Benefits of Pulumi

Real Code

Pulumi is infrastructure as real code. This means you get all the benefits of your favorite language and tool for provisioning infrastructure: code completion, error checking, versioning, IDE support, etc. - without the need to manage limited DSL syntax.

Familiar Constructs

Real languages means you get familiar constructs like for loops, functions, and classes - cutting boilerplate and enforcing best practices. Pulumi lets you leverage existing package management tools and techniques.

Ephemeral Infrastructure

Pulumi has deep support for cloud native technologies, like Kubernetes, and supports advanced deployment scenarios that cannot be expressed with Terraform. Pulumi is a proud member of the Cloud Native Computing Foundation (CNCF).

TF Provider Integration

Pulumi is able to adapt any Terraform Provider for use with Pulumi, enabling management of any infrastructure supported by the Terraform Providers ecosystem using Pulumi programs. Find out more here.

Take advantage of real coding features with Pulumi

Pulumi provides a more expressive and efficient way to define cloud resources:

  • Use variable loops, not copy/paste
  • Use any Node libaries (or Python/Go)
  • On-the-fly error checking
  • Freeform code instead of complex interpolations

Find many other examples here.

import * as aws from "@pulumi/aws";
import { readFileSync, readdirSync } from "fs";
import { join as pathjoin } from "path";

const bucket = new aws.s3.Bucket("mybucket");

const folder = "./files";
let files = readdirSync(folder);
for (let file of files) {
    const object = new aws.s3.BucketObject(file, {
        bucket: bucket,
        content: readFileSync(pathjoin(folder, file)).toString("utf8")

export const bucketname =;    
resource "aws_s3_bucket" "mybucket" {
    bucket_prefix = "mybucket"

resource "aws_s3_bucket_object" "data_txt" {
    key        = "data.txt"
    bucket     = "${}"
    source     = "./files/data.txt"

resource "aws_s3_bucket_object" "index_html" {
    key        = "index.html"
    bucket     = "${}"
    source     = "./files/index.html"

resource "aws_s3_bucket_object" "index_js" {
    key        = "index.js"
    bucket     = "${}"
    source     = "./files/index.js"

resource "aws_s3_bucket_object" "main.css" {
    key        = "main.css"
    bucket     = "${}"
    source     = "./files/main.css"

resource "aws_s3_bucket_object" "favicon.ico" {
    key        = "favicon.ico"
    bucket     = "${}"
    source     = "./files/favicon.ico"

output "bucketname" {
    value = "${}"

Productive cloud native programming

Pulumi is designed with cloud native computing in mind - from containers to serverless, providing a productive model for quickly building and deploying apps:

  • Rich, built in support for event handlers
  • Easy-to-use in-line Lambdas for simple functions
  • Use JavaScript for both infrastructure and Lambda callbacks
  • Avoid the need for significant boiler plate code

Find many other examples here.

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

// Create an S3 Bucket
const bucket = new aws.s3.Bucket("mybucket");

// Register a Lambda to handle Bucket Notification
bucket.onObjectCreated("newObj", async (ev, ctx) => {
    // Write code inline, or use a Zip

// Export the bucket name for easy scripting
export const bucketName =;  
resource "aws_s3_bucket" "mybucket" {
    bucket_prefix = "mybucket"

data "archive_file" "lambda_zip" {
    type        = "zip"
    output_path = ""

    source {
    filename = "index.js"
    content = < { 

data "aws_iam_policy_document" "lambda-assume-role-policy" {
statement {
    actions = ["sts:AssumeRole"]

    principals {
    type        = "Service"
    identifiers = [""]

resource "aws_iam_role" "lambda" {
    assume_role_policy = "${data.aws_iam_policy_document.lambda-assume-role-policy.json}"

resource "aws_lambda_function" "my_lambda" {
    filename = "${data.archive_file.lambda_zip.output_path}"
    source_code_hash = "${data.archive_file.lambda_zip.output_base64sha256}"
    function_name = "my_lambda"
    role = "${aws_iam_role.lambda.arn}"
    handler = "index.handler"
    runtime = "nodejs8.10"

resource "aws_lambda_permission" "allow_bucket" {
    statement_id  = "AllowExecutionFromS3Bucket"
    action        = "lambda:InvokeFunction"
    function_name = "${aws_lambda_function.my_lambda.arn}"
    principal     = ""
    source_arn    = "${aws_s3_bucket.mybucket.arn}"

resource "aws_s3_bucket_notification" "bucket_notification" {
    bucket = "${}"

    lambda_function {
        lambda_function_arn = "${aws_lambda_function.my_lambda.arn}"
        events              = ["s3:ObjectCreated:*"]

output "bucket_name" {
    value = "${}"

How Pulumi Works

Get started with Pulumi

Pulumi works with your favorite language, and can be used with any cloud.

Install Pulumi



Try our tutorials



Read the docs



Let Pulumi assist with your cloud infrastructure

Need help converting your Terraform templates into Pulumi code? Drop us a line.