{"id":14786799,"url":"https://github.com/serverless/aws-ai-stack","last_synced_at":"2025-05-15T01:09:10.051Z","repository":{"id":256401639,"uuid":"852418354","full_name":"serverless/aws-ai-stack","owner":"serverless","description":"AWS AI Stack – A ready-to-use, full-stack boilerplate project for building serverless AI applications on AWS","archived":false,"fork":false,"pushed_at":"2024-11-12T06:32:27.000Z","size":374,"stargazers_count":974,"open_issues_count":4,"forks_count":88,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-05-13T04:00:04.060Z","etag":null,"topics":["aws","aws-bedrock","aws-lambda","claude-ai","full-stack","llama3","serverless","serverless-framework"],"latest_commit_sha":null,"homepage":"https://awsaistack.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/serverless.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-04T19:13:23.000Z","updated_at":"2025-05-12T21:24:56.000Z","dependencies_parsed_at":"2024-09-29T03:01:21.020Z","dependency_job_id":"50434a3b-76f2-4094-a98f-7ef9b3283a2b","html_url":"https://github.com/serverless/aws-ai-stack","commit_stats":{"total_commits":32,"total_committers":5,"mean_commits":6.4,"dds":0.5625,"last_synced_commit":"06192019156c5f91b447b133e8c8ec91386acf80"},"previous_names":["serverless/aws-ai-stack"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverless%2Faws-ai-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverless%2Faws-ai-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverless%2Faws-ai-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serverless%2Faws-ai-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/serverless","download_url":"https://codeload.github.com/serverless/aws-ai-stack/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254254042,"owners_count":22039792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-bedrock","aws-lambda","claude-ai","full-stack","llama3","serverless","serverless-framework"],"created_at":"2024-09-17T08:00:35.313Z","updated_at":"2025-05-15T01:09:05.043Z","avatar_url":"https://github.com/serverless.png","language":"JavaScript","readme":"[![AWS AI Stack](https://github.com/user-attachments/assets/0550b6d6-5b97-4549-92a0-9c919d8e0b45)](https://awsaistack.com)\n\n**AWS AI Stack** – A ready-to-use, full-stack boilerplate project for building serverless AI applications on AWS. A great fit for those seeking a trusted AWS foundation for AI apps and access to powerful LLM models via Bedrock ​​that keep your app’s data separate from model providers.\n\n\n**[View the Live Demo – awsaistack.com](https://awsaistack.com)**\n\nUse this as a boilerplate project to create an AI Chat bot, authentication services, business logic, async workers, all on AWS Lambda, API Gateway, DynamoDB, and EventBridge.\n\nThis is a true serverless architecture, so you only pay for what you use, not for idle time. Some services, like DynamoDB, or AWS Bedrock trained models, may have additional storage costs.\n\n\u003ca href=\"https://awsaistack.com\" target=\"_blank\"\u003e\u003cimg width=\"2000\" alt=\"serverless-framework-v4-aws-ai-stack-screenshots\" src=\"https://github.com/user-attachments/assets/fb25ed2d-6077-4a5f-94f2-121ba59213c6\"\u003e\u003c/a\u003e\n\n# Features\n\n- **Full-Stack Application**\n  - Backend: API (AWS API Gateway V2, AWS Lambda), Event-driven architecture (AWS Event-Bridge, AWS Lambda), Database (AWS DynamoDB), AI (AWS Bedrock)\n  - Frontend: Vanilla React app.\n- **AI Chat \u0026 Streaming Responses**\n  - Full serverless AI Chat architecture w/ streaming responses on AWS Lambda.\n- **Multiple AI Models \u0026 Data Privacy**\n  - Use one or multiple models via AWS Bedrock: Claude 3.5 Sonnet, Llama3.1, Mistral Large 2, and many more.\n  - App data never leaves AWS and is not sent to model providers.\n- **100% Serverless**\n  - This is a true serverless architecture. It auto-scales and you only pay when users use it. Some services may have additional storage costs.\n- **Custom Domain Names**\n  - Custom domain names for API Gateway services using the `serverless-domain-manager` plugin\n  - Custom domain names for Lambda services using CloudFront Distributions\n- **API \u0026 Event-Driven**\n  - Express.js API placeholder service for your business logic\n  - Shared EventBridge to public \u0026 subscribe to events\n  - Worker service to process events from EventBridge\n- **Built-In Authentication**\n  - API Gateway authorizer\n  - Login \u0026 Registration API on Lambda with Express.js\n  - DynamoDB table to store user information\n  - Shared library to provide JWT token authentication\n  - Frontend website that uses login \u0026 registration API\n- **Multi-Environment**\n  - Shared configuration for all services.\n  - Separated configuration for different environments.\n- **Domain Oriented Architecture**\n  - This project is domain-oriented so you can easily remove the pieces you don't need, like AI Chat, authentication, etc.\n- **CI/CD with Github Action**\n  - Github Actions to deploy the services to prod.\n  - Github Actions to deploy PRs \u0026 remove services after merge.\n\n# Getting Started\n\n## 1. Install dependencies\n\n**Install Serverless Framework**\n\n```\nnpm i -g serverless\n```\n\n**Install NPM dependencies**\n\nThis project is structured as a monorepo with multiple services. Each service\nhas its own `package.json` file, so you must install the dependencies for each\nservice. Running `npm install` in the root directory will install the\ndependencies for all services.\n\n```\nnpm install\n```\n\n**Setup AWS Credentials**\n\nIf you haven't already, setup your AWS Credentials. You can follow the [AWS Credentials doc](https://www.serverless.com/framework/docs/providers/aws/guide/credentials)\nfor step-by-step instructions.\n\n## 2. Enable AWS Bedrock Models\n\nThis example requires the `meta.llama3-70b-instruct-v1:0` AWS Bedrock\nModel to be enabled. By default, AWS does not enable these models, you must go\nto the [AWS Console](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/models)\nand individually request access to the AI Models.\n\nThere is no cost to enable the models, but you must request access to use them.\n\nUpon request, it may take a few minutes for AWS to enable the model. Once they\nare enabled, you will receive an email from AWS confirming the model is enabled.\n\nSome users have reported issues with getting models enabled on AWS Bedrock. Make\nsure you have sufficient permissions in AWS to enable the models first. Often, \nAWS accounts that are new or have not historically had a monthly invoice over a few\ndollars may require contacting AWS to enable models.\n\n## 3. Deploy \u0026 start developing\n\nNow you are ready to deploy the services. This will deploy all the services\nto your AWS account. You can deploy the services to the `default` stage, which\nis the default stage for development.\n\n**Deploy the services**\n\n```\nserverless deploy\n```\n\nAt this point the service is live. When running the `serverless deploy` command,\nyou will see the output of the services that were deployed. One of those\nservices is the `web` service, which is the website service. To view the app,\ngo to the URL in the `endpoint: ANY - ` section for the `web` service.\n\n```\nDeploying \"web\" to stage \"dev\" (us-east-1)\n\nendpoint: ANY - https://ps5s7dd634.execute-api.us-east-1.amazonaws.com\nfunctions:\n  app: web-dev-app (991 kB)\n\n```\n\nOnce you start developing it is easier to run the service locally for faster\niteration. We recommend using [Serverless Dev Mode](https://www.serverless.com/framework/docs/providers/aws/cli-reference/dev).\nYou can run Dev Mode for individual services. This emulates Lambda locally and\nproxies requests to the real service.\n\n```\nserverless auth dev\n```\n\nOnce done, you can redeploy individual services using the `serverless` command\nwith the service name.\n\n```\nserverless auth deploy\n```\n\nThe `website` service is a static website that is served from an AWS Lambda\nfunction. As such, it can run locally without needing to use Dev Mode. However,\nit has a dependency on the AI Chat service and the Auth service, so you must\nconfigure environment variables locally.\n\n```\n# If you have the jq CLI command installed you can use that with the --json flag\n# on serverless info to get the URLs from the deployed services. If you do not\n# have jq installed, you can get the URLs by running \"serverless auth info\" and\n# \"serverless ai-chat info\" and copying the URLs manually into the environment\n# variables.\nexport VITE_CHAT_API_URL=$(serverless aiChatApi info --json | jq -r '.outputs[] | select(.OutputKey == \"ChatApiUrl\") | .OutputValue')\nexport VITE_AUTH_API_URL=$(serverless auth info --json | jq -r '.outputs[] | select(.OutputKey == \"AuthApiUrl\") | .OutputValue')\n\n# now you can run the local development server\ncd website/app\nnpm run build\n```\n\n## 4. Prepare \u0026 release to prod\n\nNow that the app is up and running in a development environment, lets get it\nready for production by setting up a custom domain name, and setting a new\nshared secret for JWT token authentication.\n\n### Setup Custom Domain Name (optional)\n\nThis project is configured to use custom domain names. For non `prod`\ndeployments this is disabled. Deployments to `prod` are designed to use a custom\ndomain name and require additional setup:\n\n**Register the domain name \u0026 create a Route53 hosted zone**\n\nIf you haven't already, register a domain name, and create a Route53 hosted zone\nfor the domain name.\n\nhttps://us-east-1.console.aws.amazon.com/route53/v2/hostedzones?region=us-east-1#\n\n**Create a Certificate in AWS Certificate Manager**\n\nA Certificate is required in order to use SSL (`https`) with a custom domain\nname. AWS Certificate Manager (ACM) provides free SSL certificates for use with\nyour custom domain name. A certificate must first be requested, which requires\nverification, and may take a few minutes.\n\nhttps://us-east-1.console.aws.amazon.com/acm/home?region=us-east-1#/certificates/list\n\nAfter you have created the certificate, you must validate the certificate by\nfollowing the instructions in the AWS Console. This may require adding a CNAME\nrecord to your DNS provider.\n\nThis example uses a Certificate with the following full qualified domain names:\n\n```\n\nawsaistack.com\n\\*.awsaistack.com\n\n```\n\nThe base domain name, `awsaistack.com` is used for the website service\nto host the static website. The wildcard domain name,\n`*.awsaistack.com` is used for the API services,\n`api.awsaistack.com`, and `chat.awsaistack.com`.\n\n**Update serverless-compose.yml**\n\n- Update the `stages.prod.params.customDomainName` to your custom domain name.\n- Update the `stages.prod.params.customDomainCertificateARN` to the ARN of the\n  certificate you created in ACM.\n\n### Create the secret for JWT token authentication\n\nAuthentication is implemented using JWT tokens. A shared secret is used to sign\nthe JWT tokens when a user logs in. The secret is also used to verify the JWT\ntokens when a user makes a request to the API. It is important that this secret\nis kept secure and not shared.\n\nIn the `serverless-compose.yml` file, you'll see that the `sharedTokenSecret` is\nset to `\"DEFAULT\"` in the `stages.default.params` section. This is a placeholder\nvalue that is used when the secret is not provided in non-prod environments.\n\nThe `prod` stage uses the `${ssm}` parameter to retrieve the secret from AWS\nSystems Manager Parameter Store.\n\nGenerate a random secret and store it in the AWS Systems Manager Parameter Store\nwith a key like `/serverless-ai-service/shared-token`, and set it in the\n`stages.prod.params.sharedTokenSecret` parameter in the `serverless-compose.yml`\nfile:\n\n```\nsharedTokenSecret: ${ssm:/serverless-ai-service/shared-token}\n```\n\n### Deploy to prod\n\nOnce you've setup the custom domain name (optional), and created the secret, you\nare ready to deploy the service to prod.\n\n```\n\nserverless deploy --stage prod\n\n```\n\nNow you can use the service by visiting your domain name, or\nhttps://awsaistack.com. This uses the Auth service to login and\nregister users, the AI Chat service to interact with the AI Chat bot.\n\n# Architectural Overview\n\n## Serverless \u0026 Costs\n\nThis example uses serverless services like AWS Lambda, API Gateway, DynamoDB,\nEventBridge, and CloudFront. These services are designed to scale with usage,\nand you only pay for what you use. This means you do not pay for idle, and\nonly pay for the resources you consume. If you have 0 usage, you will have $0\ncost.\n\nIf you are using the custom domain names, it will require Route53 which has a\nfixed monthly cost.\n\n## Compose\n\nThis example uses Serverless Compose to share configuration across all services.\n\nIt defines the global parameters in the `serverless-compose.yml` file under\n`stages.default.params` and `stages.prod.params`. These parameters are used\nacross all services to provide shared configuration.\n\nIt also uses CloudFormation from services to set parameters on other services.\nFor example, the `auth` service publishes the CloudFormation Output\n`AuthApiUrl`, which is used by the website service.\n\n```yaml\nweb:\n  path: ./website\n  params:\n    authApiUrl: ${auth.AuthApiUrl}\n```\n\nUsing Serverless Compose also allows you to deploy all services with a single\ncommand, `serverless deploy`.\n\n## Authentication SDK Library\n\nThe `auth` service contains a shared client library that is used by the other\nservices to validate the JWT token. This library is defined as an NPM package\nand is used by the `ai-chat-api` and `business-api` services and included using\nrelative paths in the `package.json` file.\n\n## Authentication (api.awsaistack.com/auth)\n\nThe `auth` service is an Express.js-based API service that provides login and\nregistration endpoints. It uses a DynamoDB table to store user information and\nuses JWT tokens for authentication.\n\nUpon login or registration, the service returns a JWT token. These APIs are used\nby the website service to authenticate users. The token is stored in\nlocalstorage and is used to authenticate requests to the `ai-chat-api` and\n`business-api` services.\n\nThe `ai-chat-api` service uses AWS Lambda Function URLs instead of API Gateway,\nin order to support streaming responses. As such, it uses the `Auth` class from\n`auth-sdk` to validate the JWT token, instead of using an API Gateway\nauthorizer.\n\nThe `auth` service also publishes the CloudFormation Output `AuthApiUrl`, which\nis used by the website service to make requests to the `auth` service.\n\n## AI Chat (chat.awsaistack.com)\n\nIn most cases APIs on AWS Lambda use the API Gateway to expose the API. However,\nthe `ai-chat-api` service uses Lambda Function URLs instead of API Gateway, in\norder to support streaming responses as streaming responses are not supported by\nAPI Gateway.\n\nSince the `ai-chat-api` service does not use API Gateway, it does not support\ncustom domain names natively. Instead, it uses a CloudFront Distribution to\nsupport a custom domain name.\n\nTo provide the AI Chat functionality, the service uses the AWS Bedrock Models\nservice to interact with the AI Chat bot. The requests from the frontend (via\nthe API) are sent to the AWS Bedrock Models service, and the streaming response\nfrom Bedrock is sent back to the frontend via the streaming response.\n\nThe AWS Bedrock AI Model is selected using the `modelId` parameter in the\n`ai-chat-api/serverless.yml` file.\n\n```\nstages:\n  default:\n    params:\n      modelId: meta.llama3-70b-instruct-v1:0\n```\n\nThe AI Chat service also implements a simple throttling schema to limit cost\nexposure when using AWS Bedrock. It implements a monthly limit for the number\nof requests per user and a global monthly limit for all users. It uses a\nDynamoDB Table to persist the request counts and other AI usage metrics.\n\nThe inline comments provider more details on this mechanism as well as ways to\ncustomize it to use other metrics, like token usage.\n\n```\nstages:\n  default:\n    params:\n      throttleMonthlyLimitUser: 10\n      throttleMonthlyLimitGlobal: 100\n```\n\n## Website (awsaistack.com)\n\nThe website service is a simple Lambda function which uses Express to serve\nstatic assets. The service uses the `serverless-plugin-scripts` plugin to\nrun the `npm run build` command to build the website before deploying.\n\nThe build command uses the parameters to set the `REACT_APP_*` environment\nvariables, which are used in the React app to configure the API URLs.\n\nThe frontend website is built using React. It uses the `auth` service to\nlogin and register uses, and uses the `ai-chat-api` to interact with the\nAI Chat bot API.\n\n## Business API (api.awsaistack.com/business)\n\nThis is an Express.js-based API service that provides a placeholder for your\nbusiness logic. It is configured to use the same custom domain name as the\n`auth` service, but with a different base path (`/business`).\n\nThe endpoints are protected using the `express-jwt` middleware, which uses the\nJWT token provided by the `auth` service to authenticate the user.\n\n## Business Worker\n\nThis is a placeholder function for your business logic for processing\nasynchronous events. It subscribes to events on the EventBridge and processes\nthe events.\n\nCurrently this subscribes to the `auth.register` event, which is published by\nthe `auth` service when a user registers.\n\nBoth the Business Worker and the Auth service therefore depend on the\nEventBridge which is provisioned in the `event-bus` service.\n\n## Custom Domain Name\n\nThe services which use API Gateway use the `serverless-domain-manager` plugin to\nsetup the custom domain name. More details about the plugin can be found on the\n[serverless-domain-manager plugin page](https://www.serverless.com/plugins/serverless-domain-manager).\n\nThe `api-ai-chat` service uses Lambda Function URLs instead of API Gateway, so\ncustom domain name is supported by creating a CloudFront Distribution with the\ncustom domain name and the Lambda Function URL as the origin.\n\nThe `business-api` and `auth` APIs both use the same custom domain name. Instead\nof sharing an API Gateway, they are configured to use the same domain name\nwith different base paths, one for each service.\n\n# API Usage\n\nBelow are a few simple API requests using the `curl` command.\n\n## User Registration API\n\n```\ncurl -X POST https://api.awsaistack.com/auth/register \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\": \"me@example.com\", \"password\": \"password\"}'\n```\n\n## User Login API\n\n```\ncurl -X POST https://api.awsaistack.com/auth/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\": \"me@example.com\", \"password\": \"password\"}'\n```\n\nIf you have `jq` installed, you can wrap the login request in a command to set\nthe token as an environment variable so you can use the token in subsequent\nrequests.\n\n```\nexport SERVERLESS_EXAMPLE_TOKEN=$(curl -X POST https://api.awsaistack.com/auth/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\": \"me@example.com\", \"password\": \"password\"}' \\\n| jq -r '.token')\n```\n\n## Chat API\n\nYou can also use the Chat API directly; however, the response payload is a\na stream of JSON objects containing the response and other metadata. Each buffer\nmay also contain multiple JSON objects.\n\nThis endpoint is authenticated and requires the JWT token from the login API.\n\n```\ncurl -N -X POST https://chat.awsaistack.com/ \\\n  -H 'Content-Type: application/json' \\\n  -H \"Authorization: Bearer $SERVERLESS_EXAMPLE_TOKEN\" \\\n  -d '[{\"role\":\"user\",\"content\":[{\"text\":\"What makes the serverless framework so great?\"}]}]'\n```\n\n## Business Logic API\n\nThis endpoint is also authenticated and requires the JWT token from the login\nAPI. The response is a simple message.\n\n```\ncurl -X GET https://api.awsaistack.com/business/ \\\n  -H 'Content-Type: application/json' \\\n  -H \"Authorization: Bearer $SERVERLESS_EXAMPLE_TOKEN\"\n```\n\n# Alternative Design Considerations\n\n## Sharing Domain Name between CloudFront and API Gateway\n\nThe Chat API uses CloudFront Distributions to add support for custom domain\nnames to the AWS Lambda Function URL, as it is not natively supported.\nThe Auth \u0026 Business APIs on the other hand use API Gateway which supports\ncustom domain names natively. However, an API Gateway and a CloudFront\nDistribution do not support using the same hostname as they both require a CNAME\nrecord.\n\nFor these two services to share the same domain name, consider using the\nCloudFront distribution to proxy the API Gateway requests. This would allow\nboth services to use the same domain name, and would also allow the Chat API\nto use the same domain name as the other services.\n\n## Using API Gateway to share a custom domain name\n\nIn this configuration, the Auth and Business APIs use the paths `/auth` and\n`/business` respectively on `api.awsaistack.com`. The Custom Domain\nName Path Mapping was used in the Custom Domain Name support in API Gateway\nto use the same domain name but shared across multiple API Gateway instances.\n\nAlternatively, you can use a single API Gateway and map the paths to the\nrespective services. This would allow you to use the same domain name for\nmultiple services, and would also allow you to use the same authorizer for\nall the services. However, sharing an API Gateway instance may have performance\nimplications at scale, which is why this example uses separate API Gateway\ninstances for each service.\n\n## Schema validation\n\nThe `auth`, `business-api`, and `chat-api` all validate the user input, and in\nthe case of `chat-api` use Zod to validate the schema. Consider including\nschema validation on all API requests using a library like Zod, and/or\nExpress.js middleware.\n\n## Static website hosting\n\nThis example, for simplicity, hosts the static assets from an AWS Lambda\nFunction. This is not recommended for production, and you should consider\nusing a static website hosting service like S3 or CloudFront to host your\nwebsite. Consider using one of the following plugins to deploy your website:\n\n- [serverless-finch](https://www.serverless.com/plugins/serverless-finch)\n- [Lift Website Component](https://www.serverless.com/plugins/serverless-lift#single-page-app)\n\n## Using Lambda Authorizers\n\nThis example uses a custom authorization method using JWT tokens for the\n`ai-chat-api` service, which doesn't use API Gateway.\n\nThe `business-api` is based on Express.js and uses the `authMiddleware` method\nin the `auth-sdk` to validate the JWT token.\n\nAPI Gateway supports Lambda Authorizers which can be used to validate JWT tokens\nbefore the request is passed to the Lambda Function. This is a more robust\nsolution than the custom method used in this example, and should be considered\nfor production services. This method will not work for the `ai-chat-api` service\nas it does not use API Gateway.\n\n## Deploying with CI/CD\n\nUsing Github Actions this example deploys all the services using Serverless\nCompose. This ensures that any changes to the individual services or the\n`serverless-compose.yml` will reevaluate the interdependent parameters. However,\nall services are redeployed on any change in the repo, which may not be\nnecessary.\n\nConsider using a more fine-grained approach to deploying services, such as\nonly deploying the services that have changed by using the `serverless \u003cservice\u003e\ndeploy` command.\n\n##\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserverless%2Faws-ai-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fserverless%2Faws-ai-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserverless%2Faws-ai-stack/lists"}