{"id":14957857,"url":"https://github.com/millihq/terraform-aws-next-js","last_synced_at":"2025-04-13T08:54:57.193Z","repository":{"id":37099748,"uuid":"273565964","full_name":"milliHQ/terraform-aws-next-js","owner":"milliHQ","description":"Terraform module for building and deploying Next.js apps to AWS. Supports SSR (Lambda), Static (S3) and API (Lambda) pages.","archived":false,"fork":false,"pushed_at":"2023-12-14T19:26:52.000Z","size":6087,"stargazers_count":1481,"open_issues_count":74,"forks_count":151,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-04-12T02:02:33.074Z","etag":null,"topics":["aws","nextjs","serverless","terraform-module"],"latest_commit_sha":null,"homepage":"https://registry.terraform.io/modules/milliHQ/next-js/aws","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/milliHQ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-06-19T18:55:43.000Z","updated_at":"2025-04-11T14:23:43.000Z","dependencies_parsed_at":"2024-01-18T05:31:08.269Z","dependency_job_id":null,"html_url":"https://github.com/milliHQ/terraform-aws-next-js","commit_stats":{"total_commits":828,"total_committers":40,"mean_commits":20.7,"dds":0.7282608695652174,"last_synced_commit":"f6fc50702f6a01319ac2f7adc7a80a91ebee7225"},"previous_names":["dealmore/terraform-aws-next-js","dealmore/terraform-next.js"],"tags_count":90,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milliHQ%2Fterraform-aws-next-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milliHQ%2Fterraform-aws-next-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milliHQ%2Fterraform-aws-next-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/milliHQ%2Fterraform-aws-next-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/milliHQ","download_url":"https://codeload.github.com/milliHQ/terraform-aws-next-js/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688543,"owners_count":21145763,"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","nextjs","serverless","terraform-module"],"created_at":"2024-09-24T13:15:43.164Z","updated_at":"2025-04-13T08:54:57.169Z","avatar_url":"https://github.com/milliHQ.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cblockquote\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cstrong\u003eNote\u003c/strong\u003e\n    \u003cbr /\u003e\n    The main branch currently contains the atomic deployments alpha preview.\n    \u003cbr /\u003e\n    For the lastest stable release, check out the \u003ca href=\"https://github.com/milliHQ/terraform-aws-next-js/tree/v0.x\"\u003e\u003ccode\u003ev0.x\u003c/code\u003e branch\u003c/a\u003e.\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    Please see our blog post \u003ca href=\"https://milli.is/blog/the-road-to-atomic-deployments\" target=\"_blank\" rel=\"noopener\"\u003e\"The road to Atomic Deployments\"\u003c/a\u003e\u003cbr /\u003eor watch the latest release review for more information:\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca aria-label=\"Terraform Next.js for AWS: First look at the new atomic deployments feature\" href=\"https://www.youtube.com/watch?v=NY3zKnIcLd4\" target=\"_blank\" rel=\"noopener\"\u003e\n      \u003cimg src=\"https://img.youtube.com/vi/NY3zKnIcLd4/0.jpg\" height=\"260px\"\u003e\n    \u003c/a\u003e\n\n  \u003c/p\u003e\n\u003c/blockquote\u003e\n\n---\n\n# Terraform Next.js module for AWS\n\n![CI status](https://github.com/milliHQ/terraform-aws-next-js/workflows/CI/badge.svg)\n\nA zero-config Terraform module for self-hosting Next.js sites serverless on AWS Lambda.\n\n## Features\n\nSome features are still under development, here is a list of features that are currently supported and what we plan to bring with the next releases:\n\n- ✅ \u0026nbsp;Supports any version of [Next.js](https://nextjs.org/)\n- ✅ \u0026nbsp;[Terraform](https://www.terraform.io/) `v0.15+`\n- ✅ \u0026nbsp;Unlimited parallel deployments of Next.js apps (atomic deployments)\n- ✅ \u0026nbsp;Static, SSG, Lambda and API pages (with [dynamic routes](https://nextjs.org/docs/routing/dynamic-routes))\n- ✅ \u0026nbsp;Automatic expiration of old static assets\n- ✅ \u0026nbsp;[Rewrites](https://nextjs.org/docs/api-reference/next.config.js/rewrites) \u0026 [Redirects](https://nextjs.org/docs/api-reference/next.config.js/redirects)\n- ✅ \u0026nbsp;[Image Component \u0026 Image Optimization](https://nextjs.org/docs/basic-features/image-optimization) support\n- 🚧 \u0026nbsp;[Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration)\n- ⛔️\u0026nbsp; [Middleware](https://nextjs.org/docs/advanced-features/middleware) (Not supported by Lambda@Edge / CloudFront functions)\n\n## Architecture\n\nThe Next.js Terraform module is designed as a full stack AWS app. It relies on multiple AWS services and connects them to work as a single application:\n\n![Architecture overview diagram](https://github.com/milliHQ/terraform-aws-next-js/blob/main/docs/assets/architecture.png?raw=true)\n\n## Usage\n\n### Prerequisites\n\nYou should have the following tools installed:\n\n- [Terraform](https://www.terraform.io/downloads)\n- [Node.js](https://nodejs.org)\n- [Bash](https://www.gnu.org/software/bash/) \u0026 [curl](https://curl.se/) (Should be available by default on many Linux based images or macOS)\n\n\u003e **Note:** Additionally we assume here that you already have a public [Route53 Hosted Zone](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html) associated with your AWS account.\n\u003e\n\u003e This is a requirement in the preview phase of atomic deployments, where each deployment gets a unique subdomain assigned.\n\u003e It will change once atomic deployments become generally available.\n\n### Setup the Next.js Terraform module\n\nThe Terraform module contains the system that is later used for creating new deployments and managing the aliases (domains) for your Next.js app(s).\nCreating the Terraform stack is only required on initial setup and creates the global resources (CloudFront distributions, DynamoDB tables, S3 storage) that is used for handling incoming requests to your website.\n\nCreate a new `main.tf` file in an empty folder (or add it to your existing Terraform stack) and add the following content:\n\n```tf\nterraform {\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"~\u003e 4.0\"\n    }\n  }\n}\n\n# Main region where the resources should be created in\n# Should be close to the location of your viewers\nprovider \"aws\" {\n  region = \"us-west-2\"\n}\n\n# Provider used for creating the Lambda@Edge function which must be deployed\n# to us-east-1 region (Should not be changed)\nprovider \"aws\" {\n  alias  = \"global_region\"\n  region = \"us-east-1\"\n}\n\n###########\n# Variables\n###########\n\nvariable \"custom_domain\" {\n  description = \"Your custom domain\"\n  type        = string\n  default     = \"example.com\"\n}\n\n# Assuming that the ZONE of your domain is already available in your AWS account (Route 53)\n# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/AboutHZWorkingWith.html\nvariable \"custom_domain_zone_name\" {\n  description = \"The Route53 zone name of the custom domain\"\n  type        = string\n  default     = \"example.com.\"\n}\n\n########\n# Locals\n########\n\nlocals {\n  # A wildcard domain(ex: *.example.com) has to be added when using atomic deployments:\n  aliases = [var.custom_domain, \"*.${var.custom_domain}\"]\n}\n\n#######################\n# Route53 Domain record\n#######################\n\n# Get the hosted zone for the custom domain\ndata \"aws_route53_zone\" \"custom_domain_zone\" {\n  name = var.custom_domain_zone_name\n}\n\n# Create a new record in Route 53 for the domain\nresource \"aws_route53_record\" \"cloudfront_alias_domain\" {\n  for_each = toset(local.aliases)\n\n  zone_id = data.aws_route53_zone.custom_domain_zone.zone_id\n  name    = each.key\n  type    = \"A\"\n\n  alias {\n    name                   = module.tf_next.cloudfront_domain_name\n    zone_id                = module.tf_next.cloudfront_hosted_zone_id\n    evaluate_target_health = false\n  }\n}\n\n##########\n# SSL Cert\n##########\n\n# Creates a free SSL certificate for CloudFront distribution\n# For more options (e.g. multiple domains) see:\n# https://registry.terraform.io/modules/terraform-aws-modules/acm/aws/\nmodule \"cloudfront_cert\" {\n  source  = \"terraform-aws-modules/acm/aws\"\n  version = \"~\u003e 3.0\"\n\n  domain_name               = var.custom_domain\n  zone_id                   = data.aws_route53_zone.custom_domain_zone.zone_id\n  subject_alternative_names = slice(local.aliases, 1, length(local.aliases))\n\n  wait_for_validation = true\n\n  tags = {\n    Name = \"CloudFront ${var.custom_domain}\"\n  }\n\n  # CloudFront works only with certs stored in us-east-1\n  providers = {\n    aws = aws.global_region\n  }\n}\n\n##########################\n# Terraform Next.js Module\n##########################\n\nmodule \"tf_next\" {\n  source  = \"milliHQ/next-js/aws\"\n  version = \"1.0.0-canary.4\"\n\n  cloudfront_aliases             = local.aliases\n  cloudfront_acm_certificate_arn = module.cloudfront_cert.acm_certificate_arn\n\n  deployment_name = \"atomic-deployments\"\n\n  enable_multiple_deployments      = true\n  multiple_deployments_base_domain = \"*.${var.custom_domain}\"\n\n  providers = {\n    aws.global_region = aws.global_region\n  }\n}\n\n#########\n# Outputs\n#########\n\noutput \"api_endpoint\" {\n  value = module.tf_next.api_endpoint\n}\n\noutput \"api_endpoint_access_policy_arn\" {\n  value = module.tf_next.api_endpoint_access_policy_arn\n}\n```\n\nTo create the resources in your AWS account, run the following commands:\n\n```sh\nterraform init    # Only needed on the first time running Terraform\n\nterraform plan    # (Optional) See what resources Terraform will create\nterraform apply   # Create the resources in your AWS account\n\n\u003e Apply complete!\n\u003e\n\u003e Outputs:\n\u003e\n\u003e api_endpoint = \"https://\u003capi-id\u003e.execute-api.us-west-2.amazonaws.com\"\n\u003e api_endpoint_access_policy_arn = \"arn:aws:iam::123456789012:policy/access-api\"\n```\n\nThe `api_endpoint` is later used by the CLI tool to create new deployments.\n\nWith the `api_endpoint_access_policy_arn` AWS policy you can create new users (and assign that policy) that only can use the CLI tool `tf-next` but cannot access other resources inside of your AWS account.\n\nAfter the successful deployment your Next.js app is publicly available at the CloudFront subdomain from the `cloudfront_domain_name` output.\n\n### Deploy a Next.js App\n\nFor building and deploying Next.js apps to the system we created a CLI tool called [`tf-next`](https://www.npmjs.com/package/tf-next).\n\nIt is a npm package that can be installed with:\n\n```sh\nnpm i -g tf-next@canary\n```\n\nNext, we need to build the Next.js so that it can run in a serverless environment (with AWS Lambda).\nThis is archived by running `tf-next build` in the same directory where your Next.js app is located (Right where your `package.json` or `next.config.js` files are located):\n\n```\ntf-next build\n\n\u003e All serverless functions created in: 20.791ms\n\u003e 1752924 total bytes\n\u003e Build successful!\n```\n\nNow deploy the Next.js app by running `tf-next deploy` from the same directory.\nThe deploy command communicates through a secured (and authenticated with your AWS credentials) API with the Terraform module.\n\nTo tell the command where to deploy the app, an additional `--endpoint` flag must be provided, which should use the value from the `api_endpoint` output from the `terraform apply` step:\n\n```\ntf-next deploy --endpoint https://\u003capi-id\u003e.execute-api.us-west-2.amazonaws.com\n\n\u003e Available at: https://3edade7a2bf7bb0343699af6b851bbfa.example.com/\n```\n\nThe preview deployment can now be accessed by the displayed url.  \nTo make the deployment available from a more readable url, you can use the `tf-next alias` subcommand:\n\n```\ntf-next alias set my-app.example.com 3edade7a2bf7bb0343699af6b851bbfa.example.com\n\n\u003e Available at: https://my-app.example.com/\n```\n\nFor a full list of available commands that can be used with `tf-next`, check the [command reference](https://github.com/milliHQ/terraform-aws-next-js/blob/main/packages/tf-next/README.md).\n\n## Examples\n\n- [Atomic Deployments](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/atomic-deployments)  \n  Each deployment gets a unique url from where it can be previewed.\n- [Complete](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/complete)  \n  Complete example with SSR, API and static pages.\n- [Static](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/static)  \n  Example that uses static pages only (No SSR).\n- [Next Image](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/next-image)  \n  Images are optimized on the fly by AWS Lambda.\n- [Existing CloudFront](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/with-existing-cloudfront)  \n  Use the module together with an existing CloudFront distribution that can be fully customized.\n- [Custom Domain](https://github.com/milliHQ/terraform-aws-next-js/tree/main/examples/with-custom-domain)  \n  Use the module with your own domain from Route 53.\n\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!--- BEGIN_TF_DOCS ---\u003e\n## Requirements\n\n| Name | Version |\n|------|---------|\n| terraform | \u003e= 0.15 |\n| aws | \u003e= 4.8 |\n\n## Providers\n\n| Name | Version |\n|------|---------|\n| aws | \u003e= 4.8 |\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| cloudfront\\_acm\\_certificate\\_arn | ACM certificate arn for custom\\_domain | `string` | `null` | no |\n| cloudfront\\_aliases | Aliases for custom\\_domain | `list(string)` | `[]` | no |\n| cloudfront\\_cache\\_key\\_headers | Header keys that should be used to calculate the cache key in CloudFront. | `list(string)` | \u003cpre\u003e[\u003cbr\u003e  \"Authorization\"\u003cbr\u003e]\u003c/pre\u003e | no |\n| cloudfront\\_create\\_distribution | Controls whether the main CloudFront distribution should be created. | `bool` | `true` | no |\n| cloudfront\\_external\\_arn | When using an external CloudFront distribution provide its arn. | `string` | `null` | no |\n| cloudfront\\_external\\_id | When using an external CloudFront distribution provide its id. | `string` | `null` | no |\n| cloudfront\\_minimum\\_protocol\\_version | The minimum version of the SSL protocol that you want CloudFront to use for HTTPS connections. One of SSLv3, TLSv1, TLSv1\\_2016, TLSv1.1\\_2016, TLSv1.2\\_2018 or TLSv1.2\\_2019. | `string` | `\"TLSv1\"` | no |\n| cloudfront\\_origin\\_request\\_policy | Id of a custom request policy that overrides the default policy (AllViewer). Can be custom or managed. | `string` | `null` | no |\n| cloudfront\\_price\\_class | Price class for the CloudFront distributions (main \u0026 proxy config). One of PriceClass\\_All, PriceClass\\_200, PriceClass\\_100. | `string` | `\"PriceClass_100\"` | no |\n| cloudfront\\_response\\_headers\\_policy | Id of a response headers policy. Can be custom or managed. Default is empty. | `string` | `null` | no |\n| cloudfront\\_webacl\\_id | An optional webacl2 arn or webacl id to associate with the cloudfront distribution | `string` | `null` | no |\n| create\\_image\\_optimization | Controls whether resources for image optimization support should be created or not. | `bool` | `true` | no |\n| debug\\_use\\_local\\_packages | Use locally built packages rather than download them from npm. | `bool` | `false` | no |\n| deployment\\_name | Identifier for the deployment group (only lowercase alphanumeric characters and hyphens are allowed). | `string` | `\"tf-next\"` | no |\n| enable\\_multiple\\_deployments | Controls whether it should be possible to run multiple deployments in parallel (requires multiple\\_deployments\\_base\\_domain). | `bool` | `false` | no |\n| image\\_optimization\\_lambda\\_memory\\_size | Amount of memory in MB the worker Lambda Function for image optimization can use. Valid value between 128 MB to 10,240 MB, in 1 MB increments. | `number` | `2048` | no |\n| lambda\\_attach\\_policy\\_json | Whether to deploy additional lambda JSON policies. If false, lambda\\_policy\\_json will not be attached to the lambda function. (Necessary since policy strings are only known after apply when using Terraforms data.aws\\_iam\\_policy\\_document) | `bool` | `false` | no |\n| lambda\\_attach\\_to\\_vpc | Set to true if the Lambda functions should be attached to a VPC. Use this setting if VPC resources should be accessed by the Lambda functions. When setting this to true, use vpc\\_security\\_group\\_ids and vpc\\_subnet\\_ids to specify the VPC networking. Note that attaching to a VPC would introduce a delay on to cold starts | `bool` | `false` | no |\n| lambda\\_policy\\_json | Additional policy document as JSON to attach to the Lambda Function role | `string` | `null` | no |\n| lambda\\_role\\_permissions\\_boundary | ARN of IAM policy that scopes aws\\_iam\\_role access for the lambda | `string` | `null` | no |\n| multiple\\_deployments\\_base\\_domain | Default wildcard domain where new deployments should be available. Should be in the form of *.example.com. | `string` | `null` | no |\n| tags | Tag metadata to label AWS resources that support tags. | `map(string)` | `{}` | no |\n| tags\\_s3\\_bucket | Tag metadata to label AWS S3 buckets. Overrides tags with the same name in input variable tags. | `map(string)` | `{}` | no |\n| vpc\\_security\\_group\\_ids | The list of Security Group IDs to be used by the Lambda functions. lambda\\_attach\\_to\\_vpc should be set to true for these to be applied. | `list(string)` | `[]` | no |\n| vpc\\_subnet\\_ids | The list of VPC subnet IDs to attach the Lambda functions. lambda\\_attach\\_to\\_vpc should be set to true for these to be applied. | `list(string)` | `[]` | no |\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| api\\_endpoint | API endpoint that is used by the CLI. |\n| api\\_endpoint\\_access\\_policy\\_arn | ARN of the policy that grants access to the API endpoint. |\n| cloudfront\\_custom\\_error\\_response | Preconfigured custom error response the CloudFront distribution should use. |\n| cloudfront\\_default\\_cache\\_behavior | Preconfigured default cache behavior the CloudFront distribution should use. |\n| cloudfront\\_default\\_root\\_object | Preconfigured root object the CloudFront distribution should use. |\n| cloudfront\\_domain\\_name | Domain of the main CloudFront distribution (When created). |\n| cloudfront\\_hosted\\_zone\\_id | Zone id of the main CloudFront distribution (When created). |\n| cloudfront\\_ordered\\_cache\\_behaviors | Preconfigured ordered cache behaviors the CloudFront distribution should use. |\n| cloudfront\\_origins | Preconfigured origins the CloudFront distribution should use. |\n| upload\\_bucket\\_id | n/a |\n\n\u003c!--- END_TF_DOCS ---\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n## Known issues\n\nUnder the hood this module uses a lot of [Vercel's](https://github.com/vercel/vercel/) build pipeline.\nSo issues that exist on Vercel are likely to occur on this project too.\n\n- Stack deletion (`terraform destroy`) fails on first run ([terraform-provider-aws#1721](https://github.com/hashicorp/terraform-provider-aws/issues/1721))\n\n  This is intentional because we cannot delete a Lambda@Edge function (Used by proxy module) in a synchronous way.\n  It can take up to an hour for AWS to unbind a Lambda@Edge function from it's CloudFront distribution even when the distribution is already destroyed.\n\n  **Workaround:**\n\n  After running the initial `terraform destroy` command (that failed) wait ~1 hour and run the command again.\n  This time it should run successfully and delete the rest of the stack.\n\n- Initial apply fails with error message `Error: error creating Lambda Event Source Mapping` ([#138](https://github.com/milliHQ/terraform-aws-next-js/issues/138))\n\n  There is some race condition when the permissions are created for the static deployment Lambda.\n  This should only happen on the first deployment.\n\n  **Workaround:**\n\n  You should be able to run`terraform apply` again and the stack creation would proceed without this error.\n\n## Contributing\n\nContributions are welcome!  \nIf you want to improve this module, please take a look at our [contributing guidelines](https://github.com/milliHQ/terraform-aws-next-js/tree/main/CONTRIBUTING.md) to get started.\n\n## About\n\nThis project is maintained by [milliVolt infrastructure](https://milli.is).  \nWe build custom infrastructure solutions for any cloud provider.\n\n## License\n\nApache-2.0 - see [LICENSE](./LICENSE) for details.\n\n\u003e **Note:** All sample projects in [`examples/*`](./examples) are licensed as MIT to comply with the official [Next.js examples](https://github.com/vercel/next.js/tree/canary/examples).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmillihq%2Fterraform-aws-next-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmillihq%2Fterraform-aws-next-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmillihq%2Fterraform-aws-next-js/lists"}