Serverless In Just a Few Lines of Code

Pulumi makes serverless applications easy by letting you focus on business logic and managing infrastructure in the same familiar language you’re already writing your code in.

Any code, any cloud, any language.

// Create a serverless REST API
import * as awsx from "@pulumi/awsx";

// Serve a simple REST API at `GET /hello`.
let app = new awsx.apigateway.API("my-app", {
    routes: [{
        path: "/hello",
        method: "GET",
        eventHandler: async (event) => {
            return {
                statusCode: 200,
                body: JSON.stringify({ hello: "World!" }),
            };
        },
    }],
});

export let url = app.url;

What is Serverless?

Serverless, or function-based, computing enables you to build and run applications and services without thinking about the server infrastructure on which the functions depend. 'Serverless' applications of course require servers (typically cloud infrastructure, or Kubernetes clusters), but don't require you to provision, scale, and manage any servers.

The reduced operational overhead of serverless computing means teams can focus on the business and application logic they need: the development of products vs the management of the infrastructure for them.

Building Blocks of Serverless Programming

Building serverless applications can be considered to be a composition of a series of standardized building blocks. For instance, serverless services can provide compute, storage, data storage, messaging/queues and orchestration. With just those blocks, extremely powerful applications can be composed and delivered with minimal infrastructure concerns.

Building Block AWS Azure GCP
API Lambda Functions Cloud Functions
Storage S3 Blob Storage Cloud Storage
Data Storage DynamoDB Cosmos DB Cloud Datatable
Timer CloudWatch Monitor Stackdriver Monitoring
Queue SQS Queue Storage Cloud Pub/Sub
Topic SNS Queue Storage Cloud Pub/Sub

Pulumi makes it simple to interact with serverless services available from the major cloud vendors, and with Kubernetes.

Creating a Serverless REST API

This example shows how to create a simple REST API that counts the number of times a route has been hit. To implement this API, we need a DynamoDB table, an API endpoint, and a Lambda function.

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

// Create a mapping from 'route' to a count.
let counterTable = new aws.dynamodb.Table("counterTable", {
    attributes: [{ name: "id", type: "S" }],
    hashKey: "id",
    readCapacity: 5,
    writeCapacity: 5,
});

// Create an API endpoint.
let endpoint = new awsx.apigateway.API("hello-world", {
    routes: [{
        path: "/{route+}",
        method: "GET",
        eventHandler: (req, res) => {
            let route = event.pathParameters!["route"];
            let client = new aws.sdk.DynamoDB.DocumentClient();

            // Get previous value and increment our table entry.
            let tableData = await client.get({
                TableName: counterTable.name.get(),
                Key: { id: route },
                ConsistentRead: true,
            }).promise();

            let value = tableData.Item;
            let count = (value && value.count) || 0;
            await client.put({
                TableName: counterTable.name.get(),
                Item: { id: route, count: ++count },
            }).promise();

            return {
                statusCode: 200,
                body: JSON.stringify({ route, count }),
            };
        },
    }],
});

exports.endpoint = endpoint.url;

Using storage buckets easily

Pulumi makes it easy to setup storage in the cloud. Events raised by the storage object can be handled by Lambda functions as actual lambdas in code.

This example sets up a storage bucket (using S3 on AWS) and a simple Lambda function to respond to new items being added to the bucket.

GET STARTED
const aws = require("@pulumi/aws");

// A storage bucket.
const videos = new aws.s3.Bucket("bucket");

// Trigger a Lambda function when something is added.
videos.onPut("onNewVideo", bucketArgs => {
    console.log(`*** New Item in Bucket`);
}

// Export the bucket name.
exports.bucketName = videos.bucket;

Stash info into a document database

This example uses a serverless timer that fetches the Hacker News homepage every day at 8:30AM and stashes it into a document database, making use of Pulumi’s ability to reference resources by capturing them inside of serverless lambdas.

GET STARTED
const aws = require("@pulumi/aws");

const snapshots = new aws.dynamodb.Table("snapshots", {
    attributes: [{ name: "id", type: "S", }],
    hashKey: "id", billingMode: "PAY_PER_REQUEST",
});

aws.cloudwatch.onSchedule("daily-yc-snapshot", "cron(30 8 * * ? *)", () => {
    require("https").get("https://news.ycombinator.com", res => {
        let content = "";
        res.setEncoding("utf8");
        res.on("data", chunk => content += chunk);
        res.on("end", () => new aws.sdk.DynamoDB.DocumentClient().put({
            TableName: snapshots.name.get(),
            Item: { date: Date.now(), content },
        }).promise());
    }).end();
});

Super-simple serverless cron jobs

Pulumi’s Cloud Framework has a timer module that lets you schedule cron jobs that run serverless functions. This is the easiest way to get up and running with serverless functions, because you don’t even need any other resources to trigger events from.

There are several ways to schedule a timer, depending on your stylistic preferences. These examples simply print the current time to the console on a given interval.

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

// Run a timer every minute:
aws.cloudwatch.onSchedule("everyMinute", "rate(1 minute)", async (event) => {
    console.log(`everyMinute: ${Date.now()}`);
});

// Run a timer every minute (cron-style expression):
aws.cloudwatch.onSchedule("everyMinuteCron", "cron(0 * * * * *)", async (event) => {
    console.log(`everyMinuteCron: ${Date.now()}`);
});

// Run a timer every day at 7:30 UTC:
aws.cloudwatch.onSchedule("everyDay730", "cron(30 7 * * ? *)", async (event) => {
    console.log(`everyDay730: ${Date.now()}`);
});

Post AWS SQS Messages to Slack

This example wires up a serverless AWS Lambda to an AWS SQS queue and demonstrates posting a message to Slack. This program provisions resources using Pulumi’s deployment system, but lets you write serverless code as ordinary JavaScript functions.

GET STARTED
let aws = require("@pulumi/aws");
let serverless = require("@pulumi/aws-serverless");
let config = require("./config");

let queue = new aws.sqs.Queue("mySlackQueue", { visibilityTimeoutSeconds: 180 });

serverless.queue.subscribe("mySlackPoster",
    queue, async (e) => {
    let slack = require("@slack/client");
    let client = new slack.WebClient(config.slackToken);
    for (let rec of e.Records) {
        await client.chat.postMessage({
            channel: config.slackChannel,
            text: `*Msg ${rec.messageId}*:\n${rec.body}\n`+
                `(with :love_letter: from Pulumi)`,
            as_user: true,
        });
        console.log(`Posted SQS message ${rec.messageId} to ${config.slackChannel}`);
    }
}, { batchSize: 1 });

module.exports = {
    queueURL: queue.id,
};

Subscribe to an SNS endpoint

This example uses an SNS topic to hold a list of website URLs to crawl, and does so everytime a new message arrives.

GET STARTED
import * as aws from "@pulumi/aws";
import * as fetch from "node-fetch";

const topic = new aws.sns.Topic("sites-to-process-topic");
topic.onEvent("for-each-url", async (event) => {
    const records = event.Records || [];
    for (const record of records) {
        // Fetch the contents at the URL
        const url = record.Sns.Message;
        console.log(`${url}: Getting`);
        try {
            const res = await fetch.default(url);
        } catch (err) {
            console.log(`${url}: Failed to GET`);
            return;
        }
    }
});

How Pulumi Works

1
Create

  • Code in real languages
  • Share and reuse patterns
  • Use your favorite IDE and tools

2
Deploy

  • Preview changes
  • Run pulumi up to deploy
  • Integrate with CI/CD

3
Manage

  • Audit all changes
  • Manage complex environments
  • Implement policies and controls

Get Started with Pulumi

Use Pulumi's open source SDK to create, deploy, and manage infrastructure on any cloud.

Learn how top engineering teams are using Pulumi to simplify their serverless applications.

We are building a distributed-database-as-a-service product that runs on Kubernetes clusters across multiple public clouds including GCP, AWS and others. Pulumi's declarative model, the support for real programming languages, and the uniform workflow on any cloud make our SRE team much more efficient.

Josh Imhoff
Site Reliability Engineer, Cockroach Labs

Need help with container management?

More from 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