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.

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 cloud infrastructure: code completion, error checking, versioning, IDE support, and general productivity gains — without the need to manage YAML and 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 = bucket.id;
resource "aws_s3_bucket" "mybucket" {
    bucket_prefix = "mybucket"

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

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

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

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

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

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 = bucket.id;
resource "aws_s3_bucket" "mybucket" {
    bucket_prefix = "mybucket"

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

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

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

        principals {
            type        = "Service"
            identifiers = ["lambda.amazonaws.com"]

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     = "s3.amazonaws.com"
    source_arn    = "${aws_s3_bucket.mybucket.arn}"

resource "aws_s3_bucket_notification" "bucket_notification" {
    bucket = "${aws_s3_bucket.mybucket.id}"

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

output "bucket_name" {
    value = "${aws_s3_bucket.mybucket.id}"

How Pulumi Works

How Pulumi works

Get Started with Pulumi

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

1 Try Our Tutorials
2 Read the Docs

Let Pulumi assist with your cloud infrastructure.

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

More from Pulumi

Migrating to Pulumi

Migrate to Pulumi

In this video, Pulumi CTO, Luke Hoban, discusses how to begin to migrate to Pulumi from existing tools such as CloudFormation and Terraform.

Learn more
Video thumbnail diagram

Serverless, Containers, and Infrastructure

In this blog post, we show how productive Pulumi can be at combining different aspects of cloud architecture for truly cloud native programming.

Learn more