View a markdown version of this page

Build a serverless web application using generative AI - Build a Serverless Web Application using Generative AI

Build a serverless web application using generative AI

AWS experience

Beginner

Time to complete

35 minutes

Cost to complete

Less than USD 0.10 if you complete the tutorial and delete the resources at the end

Requires

Note

Accounts created within the past 24 hours might not yet have access to the services required for this tutorial.

Last updated

September 10, 2026

Overview

In this tutorial, you learn how to use AWS Amplify to build a serverless web application powered by generative AI using Amazon Bedrock and the Claude 3.5 Sonnet foundation model. Users can enter a list of ingredients, and the application generates recipes based on the input ingredients. The application includes an HTML-based user interface for ingredient submission and a backend web app to request AI-generated recipes.

What you will accomplish

In this tutorial, you complete the following tasks:

  • Configure AWS Amplify to host your frontend application with continuous deployment built in

  • Configure Amplify Auth and enable Amazon Bedrock foundation model access

  • Build an app backend for handling requests for your web application

  • Use Amplify Data to call the serverless backend

  • Connect the app to the backend

Prerequisites

Before you start this tutorial, you need the following:

Application architecture

The following diagram provides a visual representation of the services used in this tutorial and how they are connected. This application uses AWS Amplify, a GraphQL API built with AWS AppSync, AWS Lambda, and Amazon Bedrock.

As you go through the tutorial, you learn about the services in detail and find resources that help you get up to speed with them.

Architecture diagram illustrating a serverless generative AI application on AWS, featuring user interaction through AWS Amplify, authentication via Amazon Cognito, data flow using AWS AppSync and GraphQL, AWS Lambda for compute, and Amazon Bedrock for generative AI capabilities.

Implementation

Complete the following steps to build, deploy, and run the application.

AWS Amplify offers a Git-based CI/CD workflow for building, deploying, and hosting single-page web applications or static sites with backends. When connected to a Git repository, Amplify determines the build settings for both the frontend framework and any configured backend resources, and automatically deploys updates with every code commit.

In this task, you start by creating a new React application and pushing it to a GitHub repository. You then connect the repository to AWS Amplify web hosting and deploy it to a globally available content delivery network (CDN) hosted on an amplifyapp.com domain.

Create a new React application

  1. Create the application

    1. In a new terminal or command line window, run the following command to use Vite to create a React application:

      npm create vite@latest ai-recipe-generator -- --template react-ts -y cd ai-recipe-generator npm install npm run dev
  2. Open the application

    1. In the terminal window, select and open the local link to view the Vite + React application.

Initialize a GitHub repository

In this step, you create a GitHub repository and commit your code to the repository. You need a GitHub account to complete this step. If you do not have an account, sign up on GitHub.

Note

If you have never used GitHub on your computer, follow the steps to connect to GitHub with SSH before continuing to allow connection to your account.

  1. Sign in to GitHub

    1. Sign in to the GitHub website.

  2. Start a new repository

    In the Start a new repository section, make the following selections:

    1. For Repository name, enter ai-recipe-generator, and choose the Public radio button.

    2. Then choose Create a new repository.

  3. Initialize Git

    1. Open a new terminal window, navigate to your project's root folder (ai-recipe-generator), and run the following commands to initialize a git repository and push the application to the new GitHub repository:

      Note

      Replace the SSH GitHub URL in the command with your GitHub URL.

      git init git add . git commit -m "first commit" git remote add origin git@github.com:<your-username>/ai-recipe-generator.git git branch -M main git push -u origin main

Install the Amplify packages

  1. Install Amplify

    1. Open a new terminal window, navigate to your app's root folder (ai-recipe-generator), and run the following command:

      npm create amplify@latest -y
  2. View directory

    1. Running the previous command scaffolds a lightweight Amplify project in the app's directory.

Deploy your app with AWS Amplify

  1. Open the Amplify console

    1. Sign in to the AWS Management Console in a new browser window, and open the AWS Amplify console.

    2. Choose Create new app.

  2. Select GitHub to deploy your app

    1. On the Start building with Amplify page, for Deploy your app, select GitHub, and choose Next.

  3. Authenticate with GitHub

    1. When prompted, authenticate with GitHub. You are automatically redirected back to the Amplify console.

    2. Choose the repository and main branch you created earlier.

    3. Then choose Next.

  4. Confirm the build settings

    1. Leave the default build settings, and choose Next.

  5. Review configuration

    1. Review the inputs selected, and choose Save and deploy.

  6. View your app

    1. AWS Amplify now builds your source code and deploys your app at https://...amplifyapp.com, and on every git push your deployment instance updates. It might take up to 5 minutes to deploy your app.

    2. After the build completes, choose the Visit deployed URL button to see your web app up and running live.

    The AWS Amplify dashboard showing the deployed 'ai-recipe-generator' app. Highlights include the production branch labeled as 'main', its deployed status, domain URL, last updated time, last commit (auto-build), repository link, and a prominent 'Visit deployed URL' button in the top right.

Now that you have a React web app, you configure an authentication resource for the app using AWS Amplify Auth, powered by Amazon Cognito. Amazon Cognito is a user directory service that manages user registration, authentication, account recovery, and more.

You use the AWS Management Console to enable access to Amazon Bedrock and the Claude 3.5 Sonnet foundation model, which the app uses to generate recipes.

Set up Amplify Auth

The app uses email as the default login mechanism. When users sign up, they receive a verification email. In this step, you customize the verification email that is sent to users.

  • Modify the resource file

    1. On your local machine, navigate to the ai-recipe-generator/amplify/auth/resource.ts file and update it with the following code. Then, save the file.

      import { defineAuth } from "@aws-amplify/backend"; export const auth = defineAuth({ loginWith: { email: { verificationEmailStyle: "CODE", verificationEmailSubject: "Welcome to the AI-Powered Recipe Generator!", verificationEmailBody: (createCode) => `Use this code to confirm your account: ${createCode()}`, }, }, });

Set up Amazon Bedrock model access

Amazon Bedrock provides access to foundation models from leading AI companies. For this tutorial, you need access to the Anthropic Claude 3.5 Sonnet model in the US East (N. Virginia) (us-east-1) Region.

  1. Open the Amazon Bedrock console

    1. Sign in to the AWS Management Console in a new browser window, and open the Amazon Bedrock console. Verify that you are in the US East (N. Virginia) (us-east-1) Region.

  2. Open the model catalog

    1. In the left navigation pane, under Discover, choose Model catalog.

  3. Find the Claude 3.5 Sonnet model

    1. Filter by the Anthropic provider, and then choose the Claude 3.5 Sonnet model.

  4. Request model access

    1. Choose Request model access. If this is the first time your account requests access to an Anthropic model, choose Submit use case details, complete the one-time form (a description of your intended use and a website URL), and then choose Submit. Access is typically granted immediately.

      Note

      If your account already has access to Anthropic models, the model opens directly and the use case form is not required. The form is required only once per account.

In this task, you configure a serverless function using AWS Amplify and AWS Lambda. This function takes an input parameter, the ingredients, to generate a prompt. It then sends this prompt to Amazon Bedrock through an HTTP POST request to the Claude 3.5 Sonnet model. The body of the request includes the prompt string within a messages array.

Create a Lambda function for handling requests

  1. Create a Lambda function

    1. On your local machine, navigate to the ai-recipe-generator/amplify/data folder, and create a file named bedrock.js.

  2. Add the function code

    1. Then, update the file with the following code:

      export function request(ctx) { const { ingredients = [] } = ctx.args; // Construct the prompt with the provided ingredients const prompt = `Suggest a recipe idea using these ingredients: ${ingredients.join(", ")}.`; // Return the request configuration return { resourcePath: `/model/anthropic.claude-3-5-sonnet-20241022-v2:0/invoke`, method: "POST", params: { headers: { "Content-Type": "application/json", }, body: JSON.stringify({ anthropic_version: "bedrock-2023-05-31", max_tokens: 1000, messages: [ { role: "user", content: [ { type: "text", text: prompt, }, ], }, ], }), }, }; } export function response(ctx) { // Parse the response body const parsedBody = JSON.parse(ctx.result.body); // Extract the text content from the response const res = { body: parsedBody.content[0].text, }; // Return the response return res; }

    This code defines a request function that constructs the HTTP request to invoke the Claude 3.5 Sonnet foundation model in Amazon Bedrock. The response function parses the response and returns the generated recipe.

Add Amazon Bedrock as a data source

  • Update the backend file

    1. Update the amplify/backend.ts file with the following code. Then, save the file.

      import { defineBackend } from "@aws-amplify/backend"; import { data } from "./data/resource"; import { PolicyStatement } from "aws-cdk-lib/aws-iam"; import { auth } from "./auth/resource"; const backend = defineBackend({ auth, data, }); const bedrockDataSource = backend.data.resources.graphqlApi.addHttpDataSource( "bedrockDS", "https://bedrock-runtime.us-east-1.amazonaws.com", { authorizationConfig: { signingRegion: "us-east-1", signingServiceName: "bedrock", }, } ); bedrockDataSource.grantPrincipal.addToPrincipalPolicy( new PolicyStatement({ resources: [ "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0", ], actions: ["bedrock:InvokeModel"], }) );
    2. The code adds an HTTP data source for Amazon Bedrock to your API and grants it permissions to invoke the Claude model.

In this task, you configure a custom query that references the data source and the resolver you defined in the previous task to produce a recipe based on a list of ingredients. This query uses a custom type to structure the response from Amazon Bedrock.

Set up Amplify Data

  1. Update the resource.ts file

    1. On your local machine, navigate to the ai-recipe-generator/amplify/data/resource.ts file, and update it with the following code. Then, save the file.

      import { type ClientSchema, a, defineData } from "@aws-amplify/backend"; const schema = a.schema({ BedrockResponse: a.customType({ body: a.string(), error: a.string(), }), askBedrock: a .query() .arguments({ ingredients: a.string().array() }) .returns(a.ref("BedrockResponse")) .authorization((allow) => [allow.authenticated()]) .handler( a.handler.custom({ entry: "./bedrock.js", dataSource: "bedrockDS" }) ), }); export type Schema = ClientSchema<typeof schema>; export const data = defineData({ schema, authorizationModes: { defaultAuthorizationMode: "apiKey", apiKeyAuthorizationMode: { expiresInDays: 30, }, }, });
    2. The following code defines the askBedrock query that takes an array of strings called ingredients and returns a BedrockResponse. The .handler(a.handler.custom({ entry: "./bedrock.js", dataSource: "bedrockDS" })) line sets up a custom handler for this query, defined in bedrock.js, using bedrockDS as its data source.

    Note

    The API key expires in 30 days, as set by expiresInDays: 30. If you return to this app later and see authorization failures, redeploy the backend to rotate the API key.

  2. Deploy resources

    1. Open a new terminal window, navigate to your app's project folder (ai-recipe-generator), and run the following command to deploy cloud resources into an isolated development space so you can iterate fast.

      npx ampx sandbox
  3. View confirmation message

    1. After the cloud sandbox is fully deployed, your terminal displays a confirmation message.

  4. Verify outputs file creation

    1. Verify that the amplify_outputs.json file was generated and added to your project.

In this task, you update the website you created in Step 1: Host a static website to use the Amplify UI component library to scaffold out an entire user authentication flow, allowing users to sign up, sign in, and reset their password, and invoke the GraphQL API to use the custom query for generating a recipe based on a list of ingredients.

Install the Amplify libraries

You need two Amplify libraries for your project. The main aws-amplify library contains all of the client-side APIs for connecting your app's frontend to your backend, and the @aws-amplify/ui-react library contains framework-specific UI components.

  • Install the libraries

    1. Open a new terminal window, navigate to your project's root folder (ai-recipe-generator), and run the following command to install the libraries.

      npm install aws-amplify @aws-amplify/ui-react

Style the app UI

  1. Modify the index CSS

    1. On your local machine, navigate to the ai-recipe-generator/src/index.css file, and update it with the following code to center the app UI. Then, save the file.

      :root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; font-weight: 400; color: rgba(255, 255, 255, 0.87); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; max-width: 1280px; margin: 0 auto; padding: 2rem; } .card { padding: 2em; } .read-the-docs { color: #888; } .box:nth-child(3n + 1) { grid-column: 1; } .box:nth-child(3n + 2) { grid-column: 2; } .box:nth-child(3n + 3) { grid-column: 3; }
  2. Modify the app CSS

    1. Update the src/App.css file with the following code to style the ingredients form. Then, save the file.

      .app-container { margin: 0 auto; padding: 20px; text-align: center; } .header-container { padding-bottom: 2.5rem; margin: auto; text-align: center; align-items: center; max-width: 48rem; } .main-header { font-size: 2.25rem; font-weight: bold; color: #1a202c; } .main-header .highlight { color: #2563eb; } @media (min-width: 640px) { .main-header { font-size: 3.75rem; } } .description { font-weight: 500; font-size: 1.125rem; max-width: 65ch; color: #1a202c; } .form-container { margin-bottom: 20px; } .search-container { display: flex; flex-direction: column; gap: 10px; align-items: center; } .wide-input { width: 100%; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 4px; } .search-button { width: 100%; /* Make the button full width */ max-width: 300px; /* Set a maximum width for the button */ padding: 10px; font-size: 16px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .search-button:hover { background-color: #0056b3; } .result-container { margin-top: 20px; transition: height 0.3s ease-out; overflow: hidden; } .loader-container { display: flex; flex-direction: column; align-items: center; gap: 10px; } .result { background-color: #f8f9fa; border: 1px solid #e9ecef; border-radius: 4px; padding: 15px; white-space: pre-wrap; word-wrap: break-word; color: black; font-weight: bold; text-align: left; /* Align text to the left */ }

Implement the UI

  1. Add authentication

    1. On your local machine, navigate to the ai-recipe-generator/src/main.tsx file, and update it with the following code. Then, save the file.

      import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.jsx"; import "./index.css"; import { Authenticator } from "@aws-amplify/ui-react"; ReactDOM.createRoot(document.getElementById("root")!).render( <React.StrictMode> <Authenticator> <App /> </Authenticator> </React.StrictMode> );
    2. The code uses the Amplify Authenticator component to scaffold out an entire user authentication flow, allowing users to sign up, sign in, reset their password, and confirm sign-in for multi-factor authentication (MFA).

  2. Configure the Amplify library

    1. Replace the contents of the ai-recipe-generator/src/App.tsx file with the following code, then save the file.

      import { FormEvent, useState } from "react"; import { Loader, Placeholder } from "@aws-amplify/ui-react"; import "./App.css"; import { Amplify } from "aws-amplify"; import { Schema } from "../amplify/data/resource"; import { generateClient } from "aws-amplify/data"; import outputs from "../amplify_outputs.json"; import "@aws-amplify/ui-react/styles.css"; Amplify.configure(outputs); const amplifyClient = generateClient<Schema>({ authMode: "userPool", }); function App() { const [result, setResult] = useState<string>(""); const [loading, setLoading] = useState(false); const onSubmit = async (event: FormEvent<HTMLFormElement>) => { event.preventDefault(); setLoading(true); try { const formData = new FormData(event.currentTarget); const { data, errors } = await amplifyClient.queries.askBedrock({ ingredients: [formData.get("ingredients")?.toString() || ""], }); if (!errors) { setResult(data?.body || "No data returned"); } else { console.log(errors); } } catch (e) { alert(`An error occurred: ${e}`); } finally { setLoading(false); } }; return ( <div className="app-container"> <div className="header-container"> <h1 className="main-header"> Meet Your Personal <br /> <span className="highlight">Recipe AI</span> </h1> <p className="description"> Simply type a few ingredients using the format ingredient1, ingredient2, etc., and Recipe AI will generate an all-new recipe on demand... </p> </div> <form onSubmit={onSubmit} className="form-container"> <div className="search-container"> <input type="text" className="wide-input" id="ingredients" name="ingredients" placeholder="Ingredient1, Ingredient2, Ingredient3,...etc" /> <button type="submit" className="search-button"> Generate </button> </div> </form> <div className="result-container"> {loading ? ( <div className="loader-container"> <p>Loading...</p> <Loader size="large" /> <Placeholder size="large" /> <Placeholder size="large" /> <Placeholder size="large" /> </div> ) : ( result && <p className="result">{result}</p> )} </div> </div> ); } export default App;
    2. The code starts by configuring the Amplify library with the client configuration file (amplify_outputs.json). It then generates a data client using the generateClient() function. The app presents a form for submitting a list of ingredients. After you submit the list, the app uses the data client to pass the list to the askBedrock query and retrieve the generated recipe, and then displays it to you.

  3. Launch the app

    1. Open a new terminal window, navigate to your project's root directory (ai-recipe-generator), and run the following command to launch the app:

      npm run dev
  4. Open the app

    1. Select the local host link to open the Vite + React application.

  5. Create an account

    1. Choose the Create Account tab, and use the authentication flow to create a new user by entering your email address and a password.

    2. Then, choose Create Account.

  6. Enter verification code

    1. You receive a verification code by email. Enter the verification code to log in to the app.

  7. Generate recipes

    1. When signed in, you can enter ingredients and choose Generate to generate recipes.

    A web app titled 'Meet Your Personal Recipe AI' showing an input box for typing ingredients such as chicken, white rice, yellow squash, and onion, with a 'Generate' button for creating recipes using AI.
  8. Push changes

    1. In the open terminal window, run the following command to push the changes to GitHub:

      git add . git commit -m 'connect to bedrock' git push origin main
  9. View your changes

    1. Sign in to the AWS Management Console in a new browser window, and open the AWS Amplify console.

    2. AWS Amplify automatically builds your source code and deploys your app at https://...amplifyapp.com, and on every git push your deployment instance updates. Choose the Visit deployed URL button to see your web app up and running live.

Clean up resources

In this task, you go through the steps to delete all the resources you created throughout this tutorial. It is a best practice to delete resources you are no longer using to avoid unwanted charges.

  1. Open general settings

    1. In the Amplify console, in the left navigation for the ai-recipe-generator app, choose App settings, and select General settings.

  2. Delete the app

    1. In the General settings section, choose Delete app.

Congratulations

You have created a React web app and used Amplify and Amazon Bedrock to develop an AI-powered recipe generator app. Additionally, you have deployed the app on AWS using Amplify Hosting.

Next steps

To continue building on what you learned in this tutorial, see the following resources:

To learn more about the AWS services you used in this tutorial, see the following resources: