> ## 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.

# Application with Database

> Connect an application to a database with built-in variables

This example deploys a PostgreSQL database and an application in the same environment, and gives the application the connection string of the database. To connect two services to each other, see [Linking Services Together](/terraform-provider/linking-services).

## How services connect

When you create a database, Qovery adds built-in variables to its environment. They hold its connection details, such as its internal host name. To give one of them the name your application reads, declare an alias on the application: `environment_variable_aliases` for a variable, `secret_aliases` for a secret.

Built-in variable names follow the pattern `QOVERY_<TYPE>_Z<ID>_<NAME>`:

* `<TYPE>` is the database type: `POSTGRESQL`, `MYSQL`, `MONGODB` or `REDIS`.
* `<ID>` is the first eight characters of the ID of the database, in uppercase. In Terraform: `upper(split("-", qovery_database.postgres.id)[0])`.
* `<NAME>` names the value. `HOST_INTERNAL`, `PORT`, `LOGIN` and `DEFAULT_DATABASE_NAME` are variables, and `PASSWORD` and `DATABASE_URL_INTERNAL` are secrets.

Use the `_INTERNAL` values to connect from a service that runs on the cluster. The complete list of database variables is in [Credentials and connectivity](/configuration/database#credentials-and-connectivity). Applications, containers and Helm services have built-in variables too: see [Linking Services Together](/terraform-provider/linking-services).

## Configuration

The database runs in `CONTAINER` mode, on your cluster. The application reads the connection string from `DATABASE_URL`, an alias of the database's `DATABASE_URL_INTERNAL` secret.

```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 environment"
  type        = string
}
```

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

provider "qovery" {}

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

resource "qovery_environment" "production" {
  project_id = qovery_project.demo.id
  cluster_id = var.cluster_id
  name       = "production"
  mode       = "PRODUCTION"
}

resource "qovery_database" "postgres" {
  environment_id = qovery_environment.production.id
  name           = "postgres"
  type           = "POSTGRESQL"
  version        = "16"
  mode           = "CONTAINER"
  accessibility  = "PRIVATE"
  cpu            = 250
  memory         = 512
  storage        = 10
}

locals {
  # Prefix of the built-in variables of the database, for example QOVERY_POSTGRESQL_ZA1B2C3D4.
  postgres_variables = "QOVERY_POSTGRESQL_Z${upper(split("-", qovery_database.postgres.id)[0])}"
}

resource "qovery_application" "backend" {
  environment_id = qovery_environment.production.id
  name           = "backend"

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

  cpu    = 500
  memory = 512

  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
    }
  }

  # DATABASE_URL_INTERNAL is a secret, so its alias is a secret alias.
  secret_aliases = [
    {
      key   = "DATABASE_URL"
      value = "${local.postgres_variables}_DATABASE_URL_INTERNAL"
    }
  ]
}

resource "qovery_deployment" "production" {
  environment_id = qovery_environment.production.id
  desired_state  = "RUNNING"

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

output "backend_url" {
  value = "https://${qovery_application.backend.external_host}"
}
```

At runtime, `DATABASE_URL` holds a URL of the form `postgresql://<login>:<password>@<host>:<port>/<database>`. The configuration never handles the password: Qovery resolves the alias when it deploys the application.

To deploy, set `TF_VAR_organization_id` and `TF_VAR_cluster_id`, then run `terraform init` and `terraform apply`, as in the [basic application example](/terraform-provider/basic-application#deploy).

<Tip>
  For production, you can run the database with your cloud provider's managed service: set `mode = "MANAGED"` and `instance_type`, such as `db.t3.medium` on AWS, and remove `cpu` and `memory`. The [multi-environment example](/terraform-provider/multi-environment) does this. `mode` cannot change after creation.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Multi-Environment Setup" icon="layer-group" href="/terraform-provider/multi-environment">
    Deploy the same stack to several environments
  </Card>

  <Card title="Linking Services Together" icon="link" href="/terraform-provider/linking-services">
    Connect services to each other with built-in variables
  </Card>

  <Card title="qovery_database reference" icon="book-open" href="https://registry.terraform.io/providers/qovery/qovery/latest/docs/resources/database">
    Every attribute of the database resource
  </Card>

  <Card title="Database Configuration" icon="database" href="/configuration/database">
    Container and managed databases
  </Card>
</CardGroup>
