> ## Documentation Index
> Fetch the complete documentation index at: https://qovery-gdubroeucq-qov-2319.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Environment Setup

> Deploy the same stack to development, staging and production environments

This example deploys the same application and PostgreSQL database to three environments of one project. A `locals` map holds what differs between the environments, and `for_each` creates one copy of each resource per entry.

## Configuration

```hcl variables.tf theme={null}
variable "organization_id" {
  description = "ID of the Qovery organization"
  type        = string
}

variable "cluster_id" {
  description = "ID of the cluster that runs the environments"
  type        = string
}
```

```hcl main.tf theme={null}
terraform {
  required_providers {
    qovery = {
      source  = "qovery/qovery"
      version = "~> 1.0"
    }
  }
}

provider "qovery" {}

locals {
  environments = {
    development = {
      mode                   = "DEVELOPMENT"
      branch                 = "develop"
      instances              = 1
      database_mode          = "CONTAINER"
      database_instance_type = null
      database_storage       = 10
    }
    staging = {
      mode                   = "STAGING"
      branch                 = "staging"
      instances              = 1
      database_mode          = "CONTAINER"
      database_instance_type = null
      database_storage       = 10
    }
    production = {
      mode                   = "PRODUCTION"
      branch                 = "main"
      instances              = 3
      database_mode          = "MANAGED"
      database_instance_type = "db.t3.medium"
      database_storage       = 50
    }
  }
}

resource "qovery_project" "shop" {
  organization_id = var.organization_id
  name            = "shop"
}

resource "qovery_environment" "env" {
  for_each = local.environments

  project_id = qovery_project.shop.id
  cluster_id = var.cluster_id
  name       = each.key
  mode       = each.value.mode
}

resource "qovery_database" "postgres" {
  for_each = local.environments

  environment_id = qovery_environment.env[each.key].id
  name           = "postgres"
  type           = "POSTGRESQL"
  version        = "16"
  mode           = each.value.database_mode
  instance_type  = each.value.database_instance_type
  accessibility  = "PRIVATE"
  storage        = each.value.database_storage
}

resource "qovery_application" "api" {
  for_each = local.environments

  environment_id = qovery_environment.env[each.key].id
  name           = "api"

  git_repository = {
    url    = "https://github.com/your-org/api.git"
    branch = each.value.branch
  }
  build_mode      = "DOCKER"
  dockerfile_path = "Dockerfile"

  cpu                   = 500
  memory                = 512
  min_running_instances = each.value.instances
  max_running_instances = each.value.instances

  # New commits redeploy development and staging, not production.
  auto_deploy = each.key != "production"

  ports = [
    {
      internal_port       = 8080
      external_port       = 443
      protocol            = "HTTP"
      publicly_accessible = true
    }
  ]

  healthchecks = {
    readiness_probe = {
      type = {
        http = {
          port   = 8080
          path   = "/health"
          scheme = "HTTP"
        }
      }
      initial_delay_seconds = 30
      period_seconds        = 10
      timeout_seconds       = 5
      success_threshold     = 1
      failure_threshold     = 3
    }
  }

  secret_aliases = [
    {
      key   = "DATABASE_URL"
      value = "QOVERY_POSTGRESQL_Z${upper(split("-", qovery_database.postgres[each.key].id)[0])}_DATABASE_URL_INTERNAL"
    }
  ]
}

resource "qovery_deployment" "env" {
  for_each = local.environments

  environment_id = qovery_environment.env[each.key].id
  desired_state  = "RUNNING"

  depends_on = [
    qovery_database.postgres,
    qovery_application.api,
  ]
}

output "api_urls" {
  value = { for name, app in qovery_application.api : name => "https://${app.external_host}" }
}
```

What differs between the environments:

* **Git branch**: each environment builds its own branch.
* **Instances**: production runs three instances of the application.
* **Database**: development and staging run PostgreSQL in a container on the cluster. Production uses your cloud provider's managed database service, which requires `instance_type`. `db.t3.medium` is an AWS RDS instance type: use one that your cloud provider offers. The database `mode` cannot change after creation.
* **Auto-deploy**: new commits redeploy development and staging. Production is deployed by `qovery_deployment` or from the Console.

The application reads the database connection string from `DATABASE_URL`, as explained in [Application with Database](/terraform-provider/application-with-database#how-services-connect).

## Deploy

```bash theme={null}
export TF_VAR_organization_id="<organization_id>"
export TF_VAR_cluster_id="<cluster_id>"

terraform init
terraform apply
terraform output api_urls
```

To add an environment, add an entry to `local.environments`. To keep a separate state per environment, move the resources into a module and call it from one root configuration per environment, or use workspaces: see [Advanced Patterns](/terraform-provider/advanced-patterns).

## Next steps

<CardGroup cols={2}>
  <Card title="Application with Database" icon="database" href="/terraform-provider/application-with-database">
    Connect services with built-in variables
  </Card>

  <Card title="Advanced Patterns" icon="code" href="/terraform-provider/advanced-patterns">
    Modules, workspaces and remote state
  </Card>

  <Card title="Terraform Exporter" icon="file-export" href="/terraform-provider/exporter">
    Generate the configuration of an existing environment
  </Card>

  <Card title="Terraform Registry" icon="book-open" href="https://registry.terraform.io/providers/qovery/qovery/latest/docs">
    Reference of every resource and data source
  </Card>
</CardGroup>
