React Website
This generator creates a new React website with shadcn/ui configured by default, along with the AWS CDK or Terraform infrastructure to deploy your website to the cloud as a static website hosted in S3, served by CloudFront and protected by WAF.
The generated application uses Vite as the build tool and bundler. It uses TanStack Router for type-safe routing.
Generate a React Website
Section titled “Generate a React Website”You can generate a new React Website in two ways:
- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - ts#website - Fill in the required parameters
- framework: react
- Click
Generate
pnpm nx g @aws/nx-plugin:ts#website --framework=reactyarn nx g @aws/nx-plugin:ts#website --framework=reactnpx nx g @aws/nx-plugin:ts#website --framework=reactbunx nx g @aws/nx-plugin:ts#website --framework=reactYou can also perform a dry-run to see what files would be changed
pnpm nx g @aws/nx-plugin:ts#website --framework=react --dry-runyarn nx g @aws/nx-plugin:ts#website --framework=react --dry-runnpx nx g @aws/nx-plugin:ts#website --framework=react --dry-runbunx nx g @aws/nx-plugin:ts#website --framework=react --dry-runOptions
Section titled “Options”| Parameter | Type | Default | Description |
|---|---|---|---|
| name Required | string | - | The name of the application. |
| framework | react | react | The frontend framework to use. |
| directory | string | packages | The directory of the new application. |
| subDirectory | string | - | The sub directory the project is placed in. By default this is the project name. |
| ux | none | cloudscape | shadcn | shadcn | The preferred UX provider. |
| tailwind | boolean | true | Enable TailwindCSS for utility-first styling. |
| tanstackRouter | boolean | true | Enable Tanstack router for type-safe routing. |
| infra | cloudfront-s3 | none | cloudfront-s3 | The type of infrastructure to deploy your website with. |
| iac | inherit | cdk | terraform | inherit | The preferred IaC provider. By default this is inherited from your initial selection. |
| preferInstallDependencies | boolean | true | Whether to prefer installing dependencies after the generator runs. Set to false to defer installing when batching multiple generators (an install still runs if needed so subsequent generators can compute the Nx project graph); install once at the end. |
Generator Output
Section titled “Generator Output”The generator will create the following project structure in the <directory>/<name> directory:
- index.html HTML entry point
- public Static assets
Directorysrc
- main.tsx Application entry point with React setup
- config.ts Application configuration (eg. logo)
Directorycomponents
- AppLayout Components for the overall layout and navigation bar
Directoryhooks
- useAppLayout.tsx Hook for adjusting the AppLayout from nested components (Cloudscape only)
Directoryroutes
- index.tsx Example route (or page) for TanStack Router
- styles.css Global styles
- vite.config.mts Vite and Vitest configuration
- tsconfig.json Base TypeScript configuration for source and tests
- tsconfig.app.json TypeScript configuration for source code
- tsconfig.spec.json TypeScript configuration for tests
Infrastructure
Section titled “Infrastructure”Since this generator vends infrastructure as code based on your chosen iacProvider, it will create a project in packages/common which includes the relevant CDK constructs or Terraform modules.
The common infrastructure as code project is structured as follows:
Directorypackages/common/constructs
Directorysrc
Directoryapp/ Constructs for infrastructure specific to a project/generator
- …
Directorycore/ Generic constructs which are reused by constructs in
app- …
- index.ts Entry point exporting constructs from
app
- project.json Project build targets and configuration
Directorypackages/common/terraform
Directorysrc
Directoryapp/ Terraform modules for infrastructure specific to a project/generator
- …
Directorycore/ Generic modules which are reused by modules in
app- …
- project.json Project build targets and configuration
The generator creates infrastructure as code for deploying your website based on your selected iacProvider:
Directorypackages/common/constructs/src
Directoryapp
Directorystatic-websites
- <name>.ts Infrastructure specific to your website
Directorycore
- static-website.ts Generic StaticWebsite construct
Directorypackages/common/terraform/src
Directoryapp
Directorystatic-websites
Directory<name>
- <name>.tf Module specific to your website
Directorycore
Directorystatic-website
- static-website.tf Generic static website module
Architecture
Section titled “Architecture”The deployed website has the following architecture:
Security Headers
Section titled “Security Headers”The CloudFront distribution applies a response headers policy that sets Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy and a Content-Security-Policy on all responses.
A default Content-Security-Policy is enforced. It restricts scripts and framing to mitigate XSS and clickjacking, while permitting HTTPS and WSS connections so the website can call AWS service endpoints (such as API Gateway, Cognito and Bedrock AgentCore) whose URLs are only known at deploy time. To adjust the policy (for example to tighten connect-src to your specific origins), edit the content_security_policy value in your generated static-website.ts (CDK) or static-website.tf (Terraform).
runtime-config.json is served with Cache-Control: no-cache so that browsers always fetch the latest configuration after a redeploy, rather than using a stale cached copy.
Implementing your React Website
Section titled “Implementing your React Website”The React documentation is a good place to start to learn the basics of building with React.
You can refer to the Cloudscape documentation for details about the available components and how to use them.
You can refer to the shadcn/ui documentation for details about the available components and how to use them.
Routes
Section titled “Routes”Creating a Route/Page
Section titled “Creating a Route/Page”Your website comes with TanStack Router configured by default. This makes it easy to add new routes:
- Run the Local Development Server
- Create a new
<page-name>.tsxfile insrc/routes, with its position in the file tree representing the path - Notice a
RouteandRouteComponentare automatically generated for you. You can start building your page here!
Navigating Between Pages
Section titled “Navigating Between Pages”You can use the Link component or useNavigate hook to navigate between pages:
import { Link, useNavigate } from '@tanstack/react-router';
export const MyComponent = () => { const navigate = useNavigate();
const submit = async () => { const id = await ... // Use `navigate` for redirecting after some asynchronous action navigate({ to: '/products/$id', { params: { id }} }); };
return ( <> <Link to="/products">Cancel</Link> <Button onClick={submit}>Submit</Button> </> )};For more details, check out the TanStack Router documentation.
Runtime Configuration
Section titled “Runtime Configuration”Configuration from your infrastructure is provided to your website via Runtime Configuration. This allows your website to access details such as API URLs which are not known until your application is deployed.
Infrastructure
Section titled “Infrastructure”The RuntimeConfig CDK construct can be used to add and retrieve configuration in your CDK infrastructure. The CDK constructs generated by @aws/nx-plugin generators (such as ts#api and py#api) will automatically add appropriate values to the RuntimeConfig.
Your website CDK construct will deploy the connection namespace of the runtime configuration as a runtime-config.json file to the root of your S3 bucket.
import { Stack } from 'aws-cdk-lib';import { Construct } from 'constructs';import { MyWebsite, MyApi } from ':my-scope/common-constructs';
export class ApplicationStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id);
// Website can be declared at any point — runtime config is resolved lazily new MyWebsite(this, 'MyWebsite');
// Automatically adds values to the RuntimeConfig new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(), }); }}With Terraform, runtime configuration is managed through the runtime-config modules. The Terraform modules generated by @aws/nx-plugin generators (such as ts#api and py#api) will automatically add appropriate values to the runtime configuration.
Your website Terraform module will deploy the connection namespace of the runtime configuration as a runtime-config.json file to the root of your S3 bucket.
module "asset_bucket" { source = "../../common/terraform/src/core/asset-bucket"}
# Automatically adds values to runtime configmodule "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name}
# Automatically deploys the runtime config to runtime-config.jsonmodule "my_website" { source = "../../common/terraform/src/app/static-websites/my-website"
providers = { aws.us_east_1 = aws.us_east_1 }
# Ensure API is deployed first to add to runtime config depends_on = [module.my_api]}Website Code
Section titled “Website Code”In your website, you can use the useRuntimeConfig hook to retrieve values from the runtime configuration:
import { useRuntimeConfig } from '../hooks/useRuntimeConfig';
const MyComponent = () => { const runtimeConfig = useRuntimeConfig();
// Access values in the runtime config here const apiUrl = runtimeConfig.apis.MyApi;};Local Runtime Config
Section titled “Local Runtime Config”When running the local development server, you will need a runtime-config.json file in your public directory in order for your local website to know the backend URLs, identity configuration, etc.
Your website project is configured with a load:runtime-config target which you can use to pull down the runtime-config.json file from a deployed application:
pnpm nx run <my-website>:"load:runtime-config"yarn nx run <my-website>:"load:runtime-config"npx nx run <my-website>:"load:runtime-config"bunx nx run <my-website>:"load:runtime-config"Local Development Server
Section titled “Local Development Server”The canonical command for local development is dev, which starts your website (and any local servers for APIs you’ve connected it to) with one command:
pnpm nx dev <my-website>yarn nx dev <my-website>npx nx dev <my-website>bunx nx dev <my-website>The serve target is also available for when you need to control how much of your application runs locally versus pointing at deployed AWS infrastructure. For a broader overview of local development across connected projects, including how dev behaves for projects with multiple components, see the Local Development guide.
Serve Target
Section titled “Serve Target”The serve target starts a local development server for your website. This target requires you to have deployed any supporting infrastructure that the website interacts with, and have loaded local runtime configuration.
You can run this target with the following command:
pnpm nx serve <my-website>yarn nx serve <my-website>npx nx serve <my-website>bunx nx serve <my-website>This target is useful for working on website changes while pointing to “real” deployed APIs and other infrastructure.
Dev Target
Section titled “Dev Target”The dev target starts a local development server for your website (with Vite MODE set to local-dev), as well as starting any local servers for APIs you have connected your website to via the Connection generator.
When your local website server is run via this target, runtime-config.json is automatically overridden to point to your locally running API urls.
You can run this target with the following command:
pnpm nx dev <my-website>yarn nx dev <my-website>npx nx dev <my-website>bunx nx dev <my-website>This target is useful when you are working across your website and API and wish to quickly iterate without deploying your infrastructure.
Mock Authentication
When run in this mode and no runtime-config.json is present, if you have configured Cognito Authentication (via the ts#website#auth generator), login will be skipped and requests to your local servers will not include authentication headers.
To enable login and authentication for dev, deploy your infrastructure and load runtime config.
Building
Section titled “Building”You can build your website using the build target. This runs the bundle, compile, test and lint targets, type-checking, bundling, testing and linting your website.
pnpm nx build <my-website>yarn nx build <my-website>npx nx build <my-website>bunx nx build <my-website>The bundle target uses Vite to create a production bundle in the root dist/packages/<my-website>/bundle directory. This is the deployable artifact consumed by your website infrastructure. You can run it on its own:
pnpm nx bundle <my-website>yarn nx bundle <my-website>npx nx bundle <my-website>bunx nx bundle <my-website>Testing
Section titled “Testing”Testing your website is much like writing tests in a standard TypeScript project, so please refer to the TypeScript project guide for more details.
For React specific testing, React Testing Library is already installed and available for you to use to write tests. For more details on its usage, please refer to the React Testing Library documentation.
You can run your tests using the test target:
pnpm nx test <my-website>yarn nx test <my-website>npx nx test <my-website>bunx nx test <my-website>Deploying Your Website
Section titled “Deploying Your Website”The React website generator creates CDK or Terraform infrastructure as code based on your selected iacProvider. You can use this to deploy your website.
To deploy your website, we recommend using the ts#infra generator to create a CDK application.
You can use the CDK construct generated for you in packages/common/constructs to deploy your website.
import { Stack } from 'aws-cdk-lib';import { Construct } from 'constructs';import { MyWebsite } from ':my-scope/common-constructs';
export class ApplicationStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id);
new MyWebsite(this, 'MyWebsite'); }}This sets up:
- An S3 bucket for hosting your static website files
- CloudFront distribution for global content delivery
- WAF Web ACL for security protection
- Origin Access Control for secure S3 access
- Automatic deployment of website files and runtime configuration
To deploy your website, we recommend using the terraform#project generator to create a Terraform project.
You can use the Terraform module generated for you in packages/common/terraform to deploy your website.
# Deploy websitemodule "my_website" { source = "../../common/terraform/src/app/static-websites/my-website"
providers = { aws.us_east_1 = aws.us_east_1 }}This sets up:
- An S3 bucket for hosting your static website files
- CloudFront distribution for global content delivery
- WAF Web ACL for security protection (deployed in us-east-1)
- Origin Access Control for secure S3 access
- Automatic deployment of website files and runtime configuration
Connections
Section titled “Connections”Use the connection generator to integrate this project with others in your workspace. The following connections involve this project:
