---
title: Configure with Terraform
description: Learn how to manage VPC Services using the Cloudflare Terraform provider.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/workers-vpc/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

# Configure with Terraform

VPC Services can be managed as infrastructure using the [cloudflare\_connectivity\_directory\_service ↗](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/connectivity%5Fdirectory%5Fservice) resource in the [Cloudflare Terraform provider](https://developers.cloudflare.com/terraform/).

This maps directly to the [connectivity directory](https://developers.cloudflare.com/api/resources/connectivity/subresources/directory/subresources/services/) — the underlying API that the dashboard and Wrangler CLI also use to create and manage VPC Services. The same [VPC Service configuration fields](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#vpc-service-configuration) (type, host, ports, tunnel ID) apply regardless of how the service is created.

Note

Requires Cloudflare Terraform provider v5.13.0 or later.

## VPC Service resource

The `cloudflare_connectivity_directory_service` resource creates a VPC Service in the connectivity directory. Each resource corresponds to one VPC Service entry that a Worker can bind to.

### Hostname-based configuration

When using a hostname, provide `host.hostname` with a `resolver_network` block. This parallels the hostname-based [JSON configuration example](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#configuration-examples).

```

resource "cloudflare_connectivity_directory_service" "my_private_api" {

  account_id = var.account_id

  name       = "my-private-api"

  type       = "http"

  http_port  = 80

  https_port = 443


  host = {

    hostname = "internal-api.example.com"

    resolver_network = {

      tunnel_id = var.tunnel_id

    }

  }

}


```

To use a custom DNS resolver within your private network, add `resolver_ips`:

```

resource "cloudflare_connectivity_directory_service" "my_private_api" {

  account_id = var.account_id

  name       = "my-private-api"

  type       = "http"


  host = {

    hostname = "internal-api.example.com"

    resolver_network = {

      tunnel_id    = var.tunnel_id

      resolver_ips = ["10.0.0.53"]

    }

  }

}


```

### IP-based configuration

When using IP addresses, provide `host.ipv4` and/or `host.ipv6` with a `network` block. This parallels the IP-based [JSON configuration example](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#configuration-examples).

```

resource "cloudflare_connectivity_directory_service" "my_private_api" {

  account_id = var.account_id

  name       = "my-private-api"

  type       = "http"

  http_port  = 8080

  https_port = 8443


  host = {

    ipv4 = "10.0.1.50"

    ipv6 = "fe80::1"

    network = {

      tunnel_id = var.tunnel_id

    }

  }

}


```

### TCP service configuration

For TCP services (for example, databases), set `type = "tcp"` and provide a `tcp_port`. You can optionally specify an `app_protocol` of `postgresql` or `mysql`.

```

resource "cloudflare_connectivity_directory_service" "my_database" {

  account_id   = var.account_id

  name         = "my-postgres-db"

  type         = "tcp"

  tcp_port     = 5432

  app_protocol = "postgresql"


  host = {

    ipv4 = "10.0.0.5"

    network = {

      tunnel_id = var.tunnel_id

    }

  }

}


```

### TLS certificate verification

To configure the TLS certificate verification mode for the connection to the origin, add a `tls_settings` block:

```

resource "cloudflare_connectivity_directory_service" "my_database" {

  account_id   = var.account_id

  name         = "my-postgres-db"

  type         = "tcp"

  tcp_port     = 5432

  app_protocol = "postgresql"


  host = {

    ipv4 = "10.0.0.5"

    network = {

      tunnel_id = var.tunnel_id

    }

  }


  tls_settings = {

    cert_verification_mode = "verify_ca"

  }

}


```

Valid values for `cert_verification_mode` are:

* `verify_full` (default)
* `verify_ca`
* `disabled`

Refer to [TLS certificate verification mode](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#tls-certificate-verification-mode) for details.

### Port configuration

For HTTP services, ports are optional and default to 80 (HTTP) and 443 (HTTPS). To enforce a single scheme, provide only one of `http_port` or `https_port`. Refer to [VPC Service configuration](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#vpc-service-configuration) for how scheme enforcement and port behavior work.

For TCP services, `tcp_port` is required.

## Workers binding configuration

Once a VPC Service exists, bind it to a Worker using the `vpc_service` binding type in the `bindings` array of a `cloudflare_worker_version` resource. This is equivalent to the [vpc\_services array in Wrangler configuration](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#workers-binding-configuration).

```

resource "cloudflare_worker_version" "my_worker_version" {

  account_id         = var.account_id

  worker_id          = cloudflare_worker.my_worker.id

  compatibility_date = "2025-02-21" # Set this to today's date

  main_module        = "worker.js"


  modules = [{

    name         = "worker.js"

    content_type = "application/javascript+module"

    content_file = "build/worker.js"

  }]


  bindings = [{

    type       = "vpc_service"

    name       = "PRIVATE_API"

    service_id = cloudflare_connectivity_directory_service.my_private_api.service_id

  }]

}


```

Multiple VPC Service bindings can be added to the same Worker:

```

bindings = [

  {

    type       = "vpc_service"

    name       = "PRIVATE_API"

    service_id = cloudflare_connectivity_directory_service.api.service_id

  },

  {

    type       = "vpc_service"

    name       = "PRIVATE_DATABASE"

    service_id = cloudflare_connectivity_directory_service.database.service_id

  }

]


```

The Worker code accesses each binding through `env.PRIVATE_API.fetch()` and `env.PRIVATE_DATABASE.fetch()`, as described in the [Workers Binding API](https://developers.cloudflare.com/workers-vpc/api/).

For more details on managing Workers and bindings with Terraform, refer to [Workers Infrastructure as Code](https://developers.cloudflare.com/workers/platform/infrastructure-as-code/).

## Data sources

The Terraform provider includes data sources for reading existing VPC Services without managing their lifecycle.

### Look up a single VPC Service

```

data "cloudflare_connectivity_directory_service" "existing" {

  account_id = var.account_id

  service_id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"

}


```

This is useful for binding to a VPC Service that is managed outside of your Terraform configuration (for example, created through the dashboard or Wrangler CLI).

### List VPC Services

```

data "cloudflare_connectivity_directory_services" "all_http" {

  account_id = var.account_id

  type       = "http"

}


data "cloudflare_connectivity_directory_services" "all_tcp" {

  account_id = var.account_id

  type       = "tcp"

}


```

## Resource schema reference

```

resource "cloudflare_connectivity_directory_service" "example" {

  # Required

  account_id = "your-account-id"        # Account identifier

  name       = "my-private-api"         # Human-readable name

  type       = "http"                   # Service type: "http" or "tcp"


  # HTTP-specific (optional, defaults to 80/443)

  http_port  = 80                       # HTTP port

  https_port = 443                      # HTTPS port


  # TCP-specific (tcp_port is required when type = "tcp")

  # tcp_port     = 5432                 # TCP port

  # app_protocol = "postgresql"         # Optional: "postgresql" or "mysql"


  host = {

    # Use hostname OR ipv4/ipv6, not both


    # Option A: Hostname-based

    hostname = "internal-api.example.com"

    resolver_network = {

      tunnel_id    = "tunnel-uuid"      # Required — Cloudflare Tunnel ID

      resolver_ips = ["10.0.0.53"]      # Optional — custom DNS resolver IPs

    }


    # Option B: IP-based

    # ipv4 = "10.0.1.50"               # IPv4 address

    # ipv6 = "fe80::1"                 # IPv6 address

    # network = {

    #   tunnel_id = "tunnel-uuid"      # Required — Cloudflare Tunnel ID

    # }

  }


  # Optional TLS settings

  # tls_settings = {

  #   cert_verification_mode = "verify_full"  # "verify_full", "verify_ca", or "disabled"

  # }


  # Read-only (computed by the API)

  # id         — Terraform resource ID

  # service_id — VPC Service ID (use this for Worker bindings)

  # created_at — Creation timestamp

  # updated_at — Last update timestamp

}


```

For the full schema, refer to the [Terraform registry documentation ↗](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/connectivity%5Fdirectory%5Fservice).

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/workers-vpc/","name":"Workers VPC"}},{"@type":"ListItem","position":3,"item":{"@id":"/workers-vpc/configuration/","name":"Configuration"}},{"@type":"ListItem","position":4,"item":{"@id":"/workers-vpc/configuration/vpc-services/","name":"VPC Services"}},{"@type":"ListItem","position":5,"item":{"@id":"/workers-vpc/configuration/vpc-services/terraform/","name":"Configure with Terraform"}}]}
```
