> ## Documentation Index
> Fetch the complete documentation index at: https://www.qovery.com/docs/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](/docs/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](/docs/configuration/database#credentials-and-connectivity). Applications, containers and Helm services have built-in variables too: see [Linking Services Together](/docs/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](/docs/terraform-provider/basic-application#deploy).

## Use a managed database

For production, use a managed database. Managed databases are created from a blueprint of the [service catalog](/docs/configuration/blueprints), with the [`qovery_blueprint`](https://registry.terraform.io/providers/qovery/qovery/latest/docs/resources/blueprint) resource. The Amazon RDS for PostgreSQL blueprint below needs an AWS cluster.

Replace `qovery_database.postgres`, the `postgres_variables` local and the `secret_aliases` of the application with:

```hcl theme={null}
# Amazon RDS for PostgreSQL from the service catalog. Requires an AWS cluster.
resource "qovery_blueprint" "postgres" {
  environment_id = qovery_environment.production.id
  name           = "postgres"
  blueprint      = "AWS/postgres/17"

  variables = {
    # Also names the RDS instance: it must be unique in the AWS account and region.
    db_name        = "app"
    instance_class = "db.t3.medium"
  }
}

locals {
  # Prefix of the output variables of the blueprint, for example QOVERY_OUTPUT_TERRAFORM_ZA1B2C3D4.
  postgres_outputs = "QOVERY_OUTPUT_TERRAFORM_Z${upper(split("-", qovery_blueprint.postgres.service_id)[0])}"
}

resource "qovery_application" "backend" {
  # ... the arguments of the configuration above, without secret_aliases

  # Qovery replaces each {{...}} with the matching output of the blueprint when it deploys the application.
  secrets = [
    {
      key   = "DATABASE_URL"
      value = "postgresql://{{${local.postgres_outputs}_DB_USERNAME}}:{{${local.postgres_outputs}_DB_PASSWORD}}@{{${local.postgres_outputs}_DB_ADDRESS}}:{{${local.postgres_outputs}_DB_PORT}}/{{${local.postgres_outputs}_DB_NAME}}"
    }
  ]
}
```

In `qovery_deployment`, replace `qovery_database.postgres` with `qovery_blueprint.postgres` in `depends_on`.

A blueprint publishes its outputs as variables of the environment, named `QOVERY_OUTPUT_TERRAFORM_Z<ID>_<OUTPUT>`, where `<ID>` is the first eight characters of `service_id`, in uppercase. `service_id` is the ID of the Terraform service that runs the blueprint. Terraform creates the blueprint and waits for its deployment before it creates the application, so the outputs exist when the application deploys. Reference them through `{{...}}` interpolation, not with aliases: an alias must be a secret exactly when its target is one, and the blueprint decides which outputs are secrets.

## Next steps

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

  <Card title="Linking Services Together" icon="link" href="/docs/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="/docs/configuration/database">
    Container and managed databases
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.