Skip to content

Latest commit

 

History

History

Folders and files

README.md

Deploy this example with Pulumi Deploy this example with Pulumi

Serverless React + Postgres

A full-stack serverless web app on AWS: a React single-page app served from S3 through CloudFront, a Lambda API behind the same CloudFront origin (so the browser never sees CORS), and a private Aurora Serverless v2 PostgreSQL database that only the function can reach.

The Pulumi program is split into two components:

  • components/database.ts - an Aurora Serverless v2 PostgreSQL cluster in private subnets, with its connection URL stored in AWS Secrets Manager.
  • components/edge.ts - the S3 site bucket, the Lambda API (VPC-attached, with least-privilege access to the secret), and a CloudFront distribution that routes /api/* to the function and everything else to the SPA.

The app runs on top of the aws-ts-landing-zone example: it reads that stack's networkId, privateSubnetIds, and secretsStore outputs through a StackReference, so deploy the landing zone first.

Prerequisites

  1. Install Pulumi
  2. Configure AWS credentials
  3. Install Node.js 20 or newer
  4. A deployed aws-ts-landing-zone stack in the same account and region

Deploying the example

  1. Build the React SPA:

    cd website
    npm install
    npm run build
    cd ..
  2. Build the API bundle:

    cd api
    npm install
    npm run build
    cd ..
  3. Install the Pulumi program's dependencies:

    npm install
  4. Create a new stack:

    pulumi stack init dev
  5. Set the AWS region and point the stack at your landing zone (use the fully-qualified <org>/<project>/<stack> name):

    pulumi config set aws:region us-west-2
    pulumi config set landingZoneStack myorg/aws-ts-landing-zone/dev
  6. Run pulumi up to preview and deploy:

    pulumi up
  7. Open the site. pulumi up prints a siteUrl; the SPA fetches /api/random and displays the number the API read from Postgres.

    curl "$(pulumi stack output apiUrl)/random"
    {"n":42}

    Note: A brand-new CloudFront distribution can take several minutes to finish deploying before the URL responds.

Project layout

  • website/ - Vite + React SPA, built to website/dist/.
  • api/ - Node 20 TypeScript handler, bundled to api/dist/handler.js with esbuild.
  • index.ts - reads the landing-zone outputs, then instantiates the Database and Edge components.

Cleaning up

To tear down the resources, run:

pulumi destroy
pulumi stack rm

Idle cost is dominated by the Aurora Serverless v2 minimum capacity, the CloudFront distribution, and S3 storage. Lambda and the Function URL cost nothing when idle.

Summary

In this example you deployed a same-origin, serverless full-stack app on AWS - React on CloudFront + S3, a VPC-attached Lambda API, and a private Aurora Serverless v2 Postgres database - layered on a shared landing zone via a StackReference.