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:
git clone --filter=blob:none --sparse https://github.com/pulumi/examples pulumi-examplesgit -C pulumi-examples sparse-checkout set aws-ts-serverless-react-postgrescd pulumi-examples/aws-ts-serverless-react-postgresA 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#
- Install Pulumi
- Configure your AWS credentials
- Install Node.js 20 or newer
- A deployed
aws-ts-landing-zonestack in the same account and region
Deploying and running the program#
-
Build the React SPA:
Terminal window cd websitenpm installnpm run buildcd .. -
Build the API bundle:
Terminal window cd apinpm installnpm run buildcd .. -
Install the Pulumi program’s dependencies:
Terminal window npm install -
Create a new stack:
Terminal window pulumi stack init dev -
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-2pulumi config set landingZoneStack myorg/aws-ts-landing-zone/dev -
Run
pulumi upto preview and deploy:Terminal window pulumi up -
Open the site.
pulumi upprints asiteUrl; the SPA fetches/api/randomand 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 towebsite/dist/.api/- Node 20 TypeScript handler, bundled toapi/dist/handler.jswith esbuild.index.ts- reads the landing-zone outputs, then instantiates theDatabaseandEdgecomponents.
Clean up#
To tear down the resources, run:
pulumi destroypulumi stack rmIdle 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.