This is a submission for the Pulumi Deploy and Document Challenge: Get Creative with Pulumi and GitHub

What I Built

I created Pulumi Preview Environment Deployer, a Node.js-based tool that automatically deploys preview environments to AWS S3 when a pull request is opened, and tears them down when the PR is closed. It uses Pulumi's Automation API to provide an efficient and isolated testing environment for every PR.

How It Works

  1. A webhook listener receives GitHub PR events.
  2. On PR open, Pulumi deploys a static website using the PR number as the stack name.
  3. On PR close, the stack is destroyed.
  4. Each preview environment is isolated by PR.

Demo

Pull request opened (or reopened) on github

Screenshot of open pull request

Event received by the nodejs server

Screenshot of event received by the nodejs server

Preview deployment start automatically for the PR

Screenshot of starting preview deployment for the PR

Preview deployment finish and output preview site url

Screenshot of preview deployment finish and output preview site url

Preview deployment accessible in the browser

Screenshot of preview deployment accessible in the browser

The deployed preview environments are tied to active pull requests and hosted on AWS S3. You can see a typical deployed preview site using a link like:

http://.s3-website-us-east-1.amazonaws.com

You can test it yourself by following the project repo README, opening a PR on your repo and watching the magic happen!

Project Repo

GitHub logo vivienogoun / pulumi-preview-deployer

Deploy preview environments for PRs using Pulumi and GitHub

Pulumi Preview Environment Deployer 🚀

This project automatically deploys preview environments to AWS S3 when a pull request is opened, and destroys them when the PR is closed — all using Pulumi's Automation API and GitHub webhooks.

✨ Features

  • Automatic deployment on PR open
  • Auto-destroy on PR close
  • Uses Pulumi's Automation API with Node.js
  • Static site hosted via AWS S3

📸 Demo

Pull request opened (or reopened) on github

Screenshot of open pull request

Event received by the nodejs server

Screenshot of event received by the nodejs server

Preview deployment start automatically for the PR

Screenshot of starting preview deployment for the PR

Preview deployment finish and output preview site url

Screenshot of preview deployment finish and output preview site url

Preview deployment accessible in the browser

Screenshot of preview deployment accessible in the browser

🛠 Tech Stack

  • Pulumi (TypeScript)
  • Node.js (Express + Automation API)
  • AWS S3
  • GitHub Webhooks
  • ngrok (for local testing)

🚀 How It Works

  1. A webhook listener receives GitHub PR events.
  2. On PR open, Pulumi deploys a static website using the PR number as the stack name.
  3. On PR close, the stack is destroyed.
  4. Each preview…




My Journey

This project was both challenging and rewarding. I started by designing a simple static site deployment to AWS using Pulumi. I ran into issues with S3 public access settings (block public ACLs and policies), which required multiple iterations and research into the correct use of BucketV2, BucketPublicAccessBlock, and ownership settings.

The real fun began with integrating Pulumi’s Automation API. I learned how to manage stacks programmatically, respond to PR events in real time, and tie everything together using GitHub webhooks and an Express server.

What stood out most was how flexible Pulumi is, letting me script infrastructure logic just like any other application code.

Using Pulumi with GitHub

I used:

  • Pulumi Automation API (in Node.js) to deploy and destroy stacks on demand
  • Pulumi AWS provider to deploy the static site to S3
  • GitHub Webhooks to trigger Pulumi workflows on PR events

The ability to programmatically manage stacks and resources via code is a game-changer — I didn’t have to rely on GitHub Actions or manual pulumi up/down commands. It’s all automatic and runs locally during development.

I didn’t use Pulumi Copilot this time, but I’m excited to try it for future use cases.

Thanks for reading and big thanks to Pulumi + DEV for hosting this challenge 🚀