> ## Documentation Index
> Fetch the complete documentation index at: https://infra.brettwporter.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js

> A Next.js website hosted on AWS utilizing OpenNext architecture.

<CodeGroup>
  ```hcl main.tf theme={null}
  /**
   * Common Data Sources
   ***/

  data "aws_region" "current" {}

  /**
   * Server Function
   ***/

  resource "aws_lambda_function" "server" {
    description      = "Server function for the website"
    filename         = var.server_function_config.filename
    function_name    = var.server_function_config.function_name
    handler          = var.server_function_config.handler
    memory_size      = var.server_function_config.memory_size
    role             = aws_iam_role.server.arn
    runtime          = var.server_function_config.runtime
    source_code_hash = filebase64sha256(var.server_function_config.filename)
    timeout          = var.server_function_config.timeout

    dynamic "tracing_config" {
      for_each = var.server_function_config.tracing_enabled ? [1] : []

      content {
        mode = "Active"
      }
    }

    dynamic "vpc_config" {
      for_each = var.vpc_config.enabled ? [1] : []

      content {
        subnet_ids         = var.vpc_config.subnet_ids
        security_group_ids = var.vpc_config.security_group_ids
      }
    }

    environment {
      variables = {
        CACHE_BUCKET_NAME         = aws_s3_bucket.cache_bucket.id
        CACHE_BUCKET_REGION       = data.aws_region.current.name
        CACHE_DYNAMO_TABLE        = "INSERT_CACHE_DYNAMO_TABLE_HERE"
        REVALIDATION_QUEUE_URL    = aws_sqs_queue.revalidation_queue.id
        REVALIDATION_QUEUE_REGION = data.aws_region.current.name
      }
    }

    tags = merge(var.shared_tags, {
      Name = var.server_function_config.function_name
    })
  }

  resource "aws_iam_role" "server_lambda" {
    name = var.server_function_config.function_name
    assume_role_policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = "sts:AssumeRole"
          Effect = "Allow"
          Principal = {
            Service = "lambda.amazonaws.com"
          }
        }
      ]
    })
  }

  resource "aws_iam_role_policy" "server_lambda" {
    name = var.server_function_config.function_name
    policy = jsondecode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
          ]
          Effect   = "Allow"
          Resource = "arn:aws:logs:*:*:*"
        },
        {
          Action = [
            "s3:GetObject",
            "s3:PutObject"
          ]
          Effect   = "Allow"
          Resource = "${aws_s3_bucket.cache_bucket.arn}/*"
        },
        {
          Action = [
            "sqs:SendMessage"
          ]
          Effect   = "Allow"
          Resource = aws_sqs_queue.revalidation_queue.arn
        },
        {
          Action = [
            "dynamodb:PutItem",
            "dynamodb:GetItem"
          ]
          Effect   = "Allow"
          Resource = "INSERT CACHE DYNAMO TABLE ARNS"
        }
      ]
    })
    role = aws_iam_role.server_lambda.id
  }

  /**
   * Image Optimization Function
   ***/

  resource "aws_lambda_function" "image_optimization" {
    architectures    = ["arm64"]
    description      = "Image Optimization function for the website"
    filename         = var.image_optimization_function_config.filename
    function_name    = var.image_optimization_function_config.function_name
    handler          = var.image_optimization_function_config.handler
    memory_size      = var.image_optimization_function_config.memory_size
    role             = aws_iam_role.image_optimization.arn
    runtime          = var.image_optimization_function_config.runtime
    source_code_hash = filebase64sha256(var.image_optimization_function_config.filename)
    timeout          = var.image_optimization_function_config.timeout

    dynamic "tracing_config" {
      for_each = var.image_optimization_function_config.tracing_enabled ? [1] : []

      content {
        mode = "Active"
      }
    }

    dynamic "vpc_config" {
      for_each = var.vpc_config.enabled ? [1] : []

      content {
        subnet_ids         = var.vpc_config.subnet_ids
        security_group_ids = var.vpc_config.security_group_ids
      }
    }

    environment {
      variables = {
        BUCKET_NAME = aws_s3_bucket.asset_files_bucket.id
      }
    }

    tags = merge(var.shared_tags, {
      Name = var.image_optimization_function_config.function_name
    })
  }

  resource "aws_iam_role" "image_optimization" {
    name = var.image_optimization_function_config.function_name
    assume_role_policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = "sts:AssumeRole"
          Effect = "Allow"
          Principal = {
            Service = "lambda.amazonaws.com"
          }
        }
      ]
    })
  }

  resource "aws_iam_role_policy" "image_optimization" {
    name = var.image_optimization_function_config.function_name
    policy = jsondecode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = [
            "s3:GetObject"
          ]
          Effect   = "Allow"
          Resource = "${aws_s3_bucket.asset_files_bucket.arn}/*"
        }
      ]
    })
    role = aws_iam_role.image_optimization.id
  }

  /**
   * Asset Files Bucket
   ***/

  resource "aws_s3_bucket" "asset_bucket" {
    bucket = var.asset_bucket_config.bucket_name

    tags = merge(var.shared_tags, {
      Name = var.asset_bucket_config.bucket_name
    })
  }

  /**
   * Revalidation Function
   ***/

  resource "aws_lambda_function" "revalidation_function" {
    description      = "Revalidation function for the website"
    filename         = var.revalidation_function_config.filename
    function_name    = var.revalidation_function_config.function_name
    handler          = var.revalidation_function_config.handler
    memory_size      = var.revalidation_function_config.memory_size
    role             = aws_iam_role.revalidation_function.arn
    runtime          = var.revalidation_function_config.runtime
    source_code_hash = filebase64sha256(var.revalidation_function_config.filename)
    timeout          = var.revalidation_function_config.timeout

    dynamic "tracing_config" {
      for_each = var.revalidation_function_config.tracing_enabled ? [1] : []

      content {
        mode = "Active"
      }
    }

    dynamic "vpc_config" {
      for_each = var.vpc_config.enabled ? [1] : []

      content {
        subnet_ids         = var.vpc_config.subnet_ids
        security_group_ids = var.vpc_config.security_group_ids
      }
    }

    tags = merge(var.shared_tags, {
      Name = var.revalidation_function_config.function_name
    })
  }

  resource "aws_iam_role" "revalidation_function" {
    name = var.revalidation_function_config.function_name
    assume_role_policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = "sts:AssumeRole"
          Effect = "Allow"
          Principal = {
            Service = "lambda.amazonaws.com"
          }
        }
      ]
    })
  }

  resource "aws_iam_role_policy" "revalidation_function" {
    name = var.revalidation_function_config.function_name
    role = aws_iam_role.revalidation_function.id
    policy = jsondecode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = [
            "sqs:ReceiveMessage",
            "sqs:DeleteMessage"
          ],
          Effect   = "Allow",
          Resource = aws_sqs_queue.revalidation_queue.arn
        }
      ]
    })
  }

  resource "aws_lambda_event_source_mapping" "revalidation_queue" {
    event_source_arn = aws_sqs_queue.revalidation_queue.arn
    function_name    = aws_lambda_function.revalidation_function.function_name
  }

  /**
   * Revalidation Queue
   ***/

  resource "aws_sqs_queue" "revalidation_queue" {
    name       = "revalidation-queue.fifo"
    fifo_queue = true

    tags = merge(var.shared_tags, {
      Name = "revalidation-queue.fifo"
    })
  }

  /**
   * Revalidation Tag-to-path Mapping DynamoDB Table
   ***/

  /**
   * Cache Files Bucket
   ***/

  resource "aws_s3_bucket" "cache_bucket" {
    bucket = var.cache_bucket_config.bucket_name

    tags = merge(var.shared_tags, {
      Name = var.cache_bucket_config.bucket_name
    })
  }

  /**
   * Warmer Function
   ***/

  resource "aws_lambda_function" "warmer" {
    description      = "Warmer function for the website"
    filename         = var.warmer_function_config.filename
    function_name    = var.warmer_function_config.function_name
    handler          = var.warmer_function_config.handler
    memory_size      = var.warmer_function_config.memory_size
    role             = aws_iam_role.warmer.arn
    runtime          = var.warmer_function_config.runtime
    source_code_hash = filebase64sha256(var.warmer_function_config.filename)
    timeout          = var.warmer_function_config.timeout

    dynamic "tracing_config" {
      for_each = var.warmer_function_config.tracing_enabled ? [1] : []

      content {
        mode = "Active"
      }
    }

    dynamic "vpc_config" {
      for_each = var.vpc_config.enabled ? [1] : []

      content {
        subnet_ids         = var.vpc_config.subnet_ids
        security_group_ids = var.vpc_config.security_group_ids
      }
    }

    environment {
      variables = {
        FUNCTION_NAME = var.server_function_config.function_name
        CONCURRENCY   = var.warmer_function_config.concurrency
      }
    }

    tags = merge(var.shared_tags, {
      Name = var.warmer_function_config.function_name
    })
  }

  resource "aws_iam_role" "warmer_lambda" {
    name = var.warmer_function_config.function_name
    assume_role_policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = "sts:AssumeRole"
          Effect = "Allow"
          Principal = {
            Service = "lambda.amazonaws.com"
          }
        }
      ]
    })
  }

  resource "aws_iam_role_policy" "warmer_lambda" {
    name = var.warmer_function_config.function_name
    policy = jsondecode({
      Version = "2012-10-17"
      Statement = [
        {
          Action = [
            "lambda:InvokeFunction"
          ]
          Effect   = "Allow"
          Resource = aws_lambda_function.server.arn
        }
      ]
    })
    role = aws_iam_role.warmer_lambda.id
  }

  /**
   * Warmer Eventbridge Cron
   ***/
  ```

  ```hcl variables.tf theme={null}
  /**
   * Server Function
   ***/

  variable "server_function_config" {
    description = "Configuration for the server function"
    type = object({
      filename        = string
      function_name   = optional(string, "server")
      handler         = optional(string, "index.mjs")
      memory_size     = optional(number, 2048)
      runtime         = optional(string, "nodejs20.x")
      timeout         = optional(number, 10)
      tracing_enabled = optional(bool, true)
    })
  }

  /**
   * Image Optimization Function
   ***/

  variable "image_optimization_function_config" {
    description = "Configuration for the image optimization function"
    type = object({
      filename        = string
      function_name   = optional(string, "image-optimization")
      handler         = optional(string, "index.mjs")
      memory_size     = optional(number, 2048)
      runtime         = optional(string, "nodejs20.x")
      timeout         = optional(number, 10)
      tracing_enabled = optional(bool, true)
    })
  }

  /**
   * Asset Files Bucket
   ***/

  variable "asset_bucket_config" {
    description = "Configuration for the asset files bucket"
    type = object({
      bucket_name = optional(string, "asset-files")
    })
    default = {
      bucket_name = "asset-files"
    }
  }

  /**
   * Revalidation Function
   ***/

  variable "revlidation_function_config" {
    description = "Configuration for the revalidation function"
    type = object({
      filename        = string
      function_name   = optional(string, "revalidation")
      handler         = optional(string, "index.mjs")
      memory_size     = optional(number, 2048)
      runtime         = optional(string, "nodejs20.x")
      timeout         = optional(number, 10)
      tracing_enabled = optional(bool, true)
    })
  }

  /**
   * Cache Files Bucket
   ***/

  variable "cache_bucket_config" {
    description = "Configuration for the cache files bucket"
    type = object({
      bucket_name = optional(string, "cache-files")
    })
    default = {
      bucket_name = "cache-files"
    }
  }

  /**
   * Warmer Function
   ***/

  variable "warmer_function_config" {
    description = "Configuration for the warmer function"
    type = object({
      filename        = string
      function_name   = optional(string, "warmer")
      handler         = optional(string, "index.mjs")
      memory_size     = optional(number, 2048)
      runtime         = optional(string, "nodejs20.x")
      timeout         = optional(number, 10)
      tracing_enabled = optional(bool, true)
      concurrency     = optional(number, 1)
    })
  }

  /**
   * Networking
   ***/

  variable "vpc_config" {
    description = "Configuration for the AWS networking"
    type = object({
      enabled            = optional(bool, false)
      subnet_ids         = optional(list(string), [])
      security_group_ids = optional(list(string), [])
    })
    default = {
      enabled            = false
      subnet_ids         = []
      security_group_ids = []
    }
  }

  /**
   * Tags
   ***/

  variable "shared_tags" {
    description = "Tags to be applied to all resources"
    type        = map(string)
    default     = {}
  }
  ```

  ```hcl outputs.tf theme={null}
  /**
   * Server Function
   ***/

  output "server_function" {
    description = "The server function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation."
    value       = aws_lambda_function.server_function
  }

  /**
   * Image Optimization Function
   ***/

  output "image_optimization_function" {
    description = "The image optimization function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation."
    value       = aws_lambda_function.image_optimization
  }

  /**
   * Asset Files Bucket
   ***/

  output "asset_bucket" {
    description = "The asset files bucket attributes. Attributes are documented under the aws_s3_bucket resource in the AWS Provider documentation."
    value       = aws_s3_bucket.asset_bucket
  }

  /**
   * Revalidation Function
   ***/

  output "revalidation_function" {
    description = "The revalidation function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation."
    value       = aws_lambda_function.revalidation
  }

  /**
   * Cache Files Bucket
   ***/

  output "cache_bucket" {
    description = "The cache files bucket attributes. Attributes are documented under the aws_s3_bucket resource in the AWS Provider documentation."
    value       = aws_s3_bucket.cache_bucket
  }

  /**
   * Warmer Function
   ***/

  output "warmer_function" {
    description = "The warmer function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation."
    value       = aws_lambda_function.warmer
  }

  /**
   * Revalidation Queue
   ***/

  output "revalidation_queue" {
    description = "The revalidation queue attributes. Attributes are documented under the aws_sqs_queue resource in the AWS Provider documentation."
    value       = aws_sqs_queue.revalidation_queue
  }
  ```

  ```hcl versions.tf theme={null}
  /**
   * Terraform and Provider versions
   ***/

  terraform {
    required_version = ">= 0.13"

    required_providers {
      aws = {
        source  = "hashicorp/aws"
        version = "~> 3.0"
      }
    }
  }
  ```

  ```md README.md theme={null}
  <!-- BEGIN_TF_DOCS -->

  ## Requirements

  | Name                                                                     | Version |
  | ------------------------------------------------------------------------ | ------- |
  | <a name="requirement_terraform"></a> [terraform](#requirement_terraform) | >= 0.13 |
  | <a name="requirement_aws"></a> [aws](#requirement_aws)                   | ~> 3.0  |

  ## Providers

  | Name                                             | Version |
  | ------------------------------------------------ | ------- |
  | <a name="provider_aws"></a> [aws](#provider_aws) | ~> 3.0  |

  ## Modules

  No modules.

  ## Resources

  | Name                                                                                                                                                          | Type        |
  | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
  | [aws_iam_role.image_optimization](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role)                                       | resource    |
  | [aws_iam_role.revalidation_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role)                                    | resource    |
  | [aws_iam_role.server_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role)                                            | resource    |
  | [aws_iam_role.warmer_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role)                                            | resource    |
  | [aws_iam_role_policy.image_optimization](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy)                         | resource    |
  | [aws_iam_role_policy.revalidation_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy)                      | resource    |
  | [aws_iam_role_policy.server_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy)                              | resource    |
  | [aws_iam_role_policy.warmer_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy)                              | resource    |
  | [aws_lambda_event_source_mapping.revalidation_queue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_event_source_mapping) | resource    |
  | [aws_lambda_function.image_optimization](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function)                         | resource    |
  | [aws_lambda_function.revalidation_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function)                      | resource    |
  | [aws_lambda_function.server](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function)                                     | resource    |
  | [aws_lambda_function.warmer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function)                                     | resource    |
  | [aws_s3_bucket.asset_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)                                           | resource    |
  | [aws_s3_bucket.cache_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)                                           | resource    |
  | [aws_sqs_queue.revalidation_queue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue)                                     | resource    |
  | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region)                                                   | data source |

  ## Inputs

  | Name                                                                                                                                    | Description                                       | Type                                                                                                                                                                                                                                                                                                                                                  | Default                                                                                    | Required |
  | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | :------: |
  | <a name="input_asset_bucket_config"></a> [asset_bucket_config](#input_asset_bucket_config)                                              | Configuration for the asset files bucket          | <pre>object({<br> bucket_name = optional(string, "asset-files")<br> })</pre>                                                                                                                                                                                                                                                                          | <pre>{<br> "bucket_name": "asset-files"<br>}</pre>                                         |    no    |
  | <a name="input_cache_bucket_config"></a> [cache_bucket_config](#input_cache_bucket_config)                                              | Configuration for the cache files bucket          | <pre>object({<br> bucket_name = optional(string, "cache-files")<br> })</pre>                                                                                                                                                                                                                                                                          | <pre>{<br> "bucket_name": "cache-files"<br>}</pre>                                         |    no    |
  | <a name="input_image_optimization_function_config"></a> [image_optimization_function_config](#input_image_optimization_function_config) | Configuration for the image optimization function | <pre>object({<br> filename = string<br> function_name = optional(string, "image-optimization")<br> handler = optional(string, "index.mjs")<br> memory_size = optional(number, 2048)<br> runtime = optional(string, "nodejs20.x")<br> timeout = optional(number, 10)<br> tracing_enabled = optional(bool, true)<br> })</pre>                           | n/a                                                                                        |   yes    |
  | <a name="input_revlidation_function_config"></a> [revlidation_function_config](#input_revlidation_function_config)                      | Configuration for the revalidation function       | <pre>object({<br> filename = string<br> function_name = optional(string, "revalidation")<br> handler = optional(string, "index.mjs")<br> memory_size = optional(number, 2048)<br> runtime = optional(string, "nodejs20.x")<br> timeout = optional(number, 10)<br> tracing_enabled = optional(bool, true)<br> })</pre>                                 | n/a                                                                                        |   yes    |
  | <a name="input_server_function_config"></a> [server_function_config](#input_server_function_config)                                     | Configuration for the server function             | <pre>object({<br> filename = string<br> function_name = optional(string, "server")<br> handler = optional(string, "index.mjs")<br> memory_size = optional(number, 2048)<br> runtime = optional(string, "nodejs20.x")<br> timeout = optional(number, 10)<br> tracing_enabled = optional(bool, true)<br> })</pre>                                       | n/a                                                                                        |   yes    |
  | <a name="input_shared_tags"></a> [shared_tags](#input_shared_tags)                                                                      | Tags to be applied to all resources               | `map(string)`                                                                                                                                                                                                                                                                                                                                         | `{}`                                                                                       |    no    |
  | <a name="input_vpc_config"></a> [vpc_config](#input_vpc_config)                                                                         | Configuration for the AWS networking              | <pre>object({<br> enabled = optional(bool, false)<br> subnet_ids = optional(list(string), [])<br> security_group_ids = optional(list(string), [])<br> })</pre>                                                                                                                                                                                        | <pre>{<br> "enabled": false,<br> "security_group_ids": [],<br> "subnet_ids": []<br>}</pre> |    no    |
  | <a name="input_warmer_function_config"></a> [warmer_function_config](#input_warmer_function_config)                                     | Configuration for the warmer function             | <pre>object({<br> filename = string<br> function_name = optional(string, "warmer")<br> handler = optional(string, "index.mjs")<br> memory_size = optional(number, 2048)<br> runtime = optional(string, "nodejs20.x")<br> timeout = optional(number, 10)<br> tracing_enabled = optional(bool, true)<br> concurrency = optional(number, 1)<br> })</pre> | n/a                                                                                        |   yes    |

  ## Outputs

  | Name                                                                                                                 | Description                                                                                                                                     |
  | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
  | <a name="output_cache_bucket"></a> [cache_bucket](#output_cache_bucket)                                              | The cache files bucket attributes. Attributes are documented under the aws_s3_bucket resource in the AWS Provider documentation.                |
  | <a name="output_image_optimization_function"></a> [image_optimization_function](#output_image_optimization_function) | The image optimization function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation. |
  | <a name="output_revalidation_function"></a> [revalidation_function](#output_revalidation_function)                   | The revalidation function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation.       |
  | <a name="output_revalidation_queue"></a> [revalidation_queue](#output_revalidation_queue)                            | The revalidation queue attributes. Attributes are documented under the aws_sqs_queue resource in the AWS Provider documentation.                |
  | <a name="output_server_function"></a> [server_function](#output_server_function)                                     | The server function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation.             |
  | <a name="output_warmer_function"></a> [warmer_function](#output_warmer_function)                                     | The warmer function attributes. Attributes are documented under the aws_lambda_function resource in the AWS Provider documentation.             |

  <!-- END_TF_DOCS -->
  ```
</CodeGroup>

## About

This is an opinated way to launch a Next.js based website on AWS.

This architecture is based on utilizing OpenNext for generation of the site bundles. Refer to [OpenNext](https://open-next.js.org/) for more information on what Next.js features it supports.

## Installation

<Steps>
  <Step title="Copy and paste all code files above into a folder.">
    Copy the main.tf, variables.tf, outputs.tf, versions.tf, and README.md into
    a folder (ex. website).
  </Step>

  <Step title="Reference the new module as a local or remote module.">
    ```hcl theme={null}
    module "website" {
      source = "path-to-copied-website-module"

      server_function_config = {
        filename = "server.zip"
      }

      image_optimization_function_config = {
        filename = "image-optimization.zip"
      }

      revlidation_function_config = {
        filename = "revlidation.zip"
      }

      warmer_function_config = {
        filename = "warmer.zip"
      }
    }
    ```
  </Step>

  <Step title="Install dependencies, prep zip bundles dependencies, and deploy!">
    Install [OpenNext](https://open-next.js.org/) and
    [Terraform](https://registry.terraform.io/) or
    [OpenTofu](https://opentofu.org/) dependencies. Then make the correct zip
    bundles via OpenNext and deploy.
  </Step>
</Steps>

## Usage

The options available to can be seen in the [variables.tf](https://github.com/brettwporter/infra/blob/main/modules/website/variables.tf) file as well as in the Next.js module [README](https://github.com/brettwporter/infra/blob/main/modules/website/README.md).
