Skip to main content

Serverless React + Postgres

A React SPA served through CloudFront, a Lambda API behind the same origin, and a private Aurora Serverless v2 (PostgreSQL) database - deployed on top of the aws-ts-landing-zone example.

This example lives in the pulumi/examples repository. Check out just this directory to use it:

Get started with this example
git clone --filter=blob:none --sparse https://github.com/pulumi/examples pulumi-examples
git -C pulumi-examples sparse-checkout set aws-ts-serverless-react-postgres
cd pulumi-examples/aws-ts-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 your AWS credentials
  3. Install Node.js 20 or newer
  4. A deployed aws-ts-landing-zone stack in the same account and region

Deploying and running the program#

  1. Build the React SPA:

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

    Terminal window
    cd api
    npm install
    npm run build
    cd ..
  3. Install the Pulumi program’s dependencies:

    Terminal window
    npm install
  4. Create a new stack:

    Terminal window
    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):

    Terminal window
    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:

    Terminal window
    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.

    Terminal window
    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.

Clean up#

To tear down the resources, run:

Terminal window
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.

Related

The infrastructure as code platform for any cloud.