Terraform is an open-source infrastructure as code (IaC) tool that allows you to define and provision cloud resources in a declarative configuration language. By codifying infrastructure, Terraform enables consistent, repeatable, and automated deployments, significantly reducing manual errors.
This guide will show you how to use Terraform to manage your Neon projects, including your branches, databases, and compute endpoints. By using Terraform with Neon, you get better control, can track changes, and automate your database setup.
Neon sponsors the following community-developed Terraform provider for managing Neon Postgres platform resources:
Terraform Provider Neon - Maintainer: Dmitry Kisler
note
This provider is not maintained or officially supported by Neon. Use at your own discretion. If you have questions about the provider, please contact the project maintainer.
Provider usage notes
-
Provider upgrades: When using
terraform init -upgrade
to update a custom Terraform provider, be aware that changes in the provider’s schema or defaults can lead to unintended resource replacements. This may occur when certain attributes are altered or reset. For example, fields previously set to specific values might be reset tonull
, forcing the replacement of the entire resource.To avoid unintended resource replacements which can result in data loss:
- Review the provider’s changelog for any breaking changes that might affect your resources before upgrading to a new version.
- For CI pipelines and auto-approved pull requests, only use
terraform init
. Runningterraform init -upgrade
should be done manually followed by plan reviews. - Run
terraform plan
before applying any changes to detect potential differences and review the behavior of resource updates. - Use lifecycle protections on critical resources to ensure they're not recreated unintentionally.
- Explicitly define all critical resource parameters in your Terraform configurations, even if they had defaults previously.
- On Neon paid plans, you can enable branch protection to prevent unintended deletion of branches and projects. To learn more, see Protected branches.
-
Provider maintenance: As Neon enhances existing features and introduces new ones, the Neon API will continue to evolve. These changes may not immediately appear in community-maintained Terraform providers. If you notice that a provider requires an update, please reach out to the maintainer by opening an issue or contributing to the provider's GitHub repository.
Prerequisites
Before you begin, ensure you have the following:
- Terraform CLI installed: If you don't have Terraform installed, download and install it from the official Terraform website. The Neon provider requires Terraform version
1.14.x
or later. - Neon Account: You'll need a Neon account. If you don't have one, sign up at neon.tech.
- Neon API key: Generate an API key from the Neon Console. Navigate to your Account Settings > API Keys. This key is required for the provider to authenticate with the Neon API. Learn more about creating API keys in Manage API keys.
Set up the Terraform Neon provider
-
Create a project directory: Create a new directory for your Terraform project and navigate into it.
mkdir neon-terraform-project cd neon-terraform-project
-
Create a
main.tf
file: This file will contain your Terraform configuration. Start by declaring the required Neon provider.terraform { required_providers { neon = { source = "kislerdm/neon" } } } provider "neon" {}
-
Initialize terraform: Run the
terraform init
command in your project directory. This command downloads and installs the Neon provider.terraform init
Configure authentication
The Neon provider needs your Neon API key to manage resources. You can configure it in two ways:
-
Directly in the provider block (Less secure): For quick testing, you can hardcode your API key directly within
provider "neon"
block. However, this method isn't recommended for production environments or shared configurations. A more secure alternative is to retrieve the API key from a secrets management service like AWS Secrets Manager or HashiCorp Vault, and then update your provider block to reflect this.provider "neon" { api_key = "<YOUR_NEON_API_KEY>" }
-
Using environment variables: The provider will automatically use the
NEON_API_KEY
environment variable if set.export NEON_API_KEY="<YOUR_NEON_API_KEY>"
If the environment variable is set, you can leave the
provider "neon"
block empty:provider "neon" {}
note
The following sections primarily detail the creation of Neon resources. To manage existing resources, use the terraform import
command. More information can be found in the Importing Existing Resources section.
Manage Neon resources
Now you can start defining Neon resources in your main.tf
file.
Managing projects
A Neon project is the top-level container for your Postgres databases, branches, and endpoints.
resource "neon_project" "my_app_project" {
name = "my-application-project"
pg_version = 16
region_id = "aws-us-east-1"
# Configure default branch settings (optional)
branch {
name = "production"
database_name = "app_db"
role_name = "app_admin"
}
# Configure default endpoint settings (optional)
default_endpoint_settings {
autoscaling_limit_min_cu = 0.25
autoscaling_limit_max_cu = 1.0
# suspend_timeout_seconds = 300
}
}
This configuration creates a new Neon project.
Key neon_project
attributes:
name
: (Optional) Name of the project.pg_version
: (Optional) PostgreSQL version (e.g., 14, 15, 16, 17).region_id
: (Optional) The region where the project will be created (e.g.,aws-us-east-1
).For up-to-date information on available regions, see Neon Regions.
branch {}
: (Optional) Block to configure the default primary branch.
Output project details: You can output computed values like the project ID or connection URI:
output "project_id" {
value = neon_project.my_app_project.id
}
output "project_connection_uri" {
description = "Default connection URI for the primary branch (contains credentials)."
value = neon_project.my_app_project.connection_uri
sensitive = true
}
output "project_default_branch_id" {
value = neon_project.my_app_project.default_branch_id
}
output "project_database_user" {
value = neon_project.my_app_project.database_user
}
For more attributes and options on managing projects, refer to the Provider's documentation.
Managing branches
You can create branches from the primary branch or any other existing branch.
resource "neon_branch" "dev_branch" {
project_id = neon_project.my_app_project.id
name = "feature-x-development"
parent_id = neon_project.my_app_project.default_branch_id # Branch from the project's primary branch
# Optional: Create a protected branch
# protected = "yes"
# Optional: Create from a specific LSN or timestamp of the parent
# parent_lsn = "..."
# parent_timestamp = 1678886400 # Unix epoch
}
Key neon_branch
attributes:
project_id
: (Required) ID of the parent project.name
: (Optional) Name for the new branch.parent_id
: (Optional) ID of the parent branch. If not specified, defaults to the project's primary branch.protected
: (Optional, String: "yes" or "no") Set to protect the branch.parent_lsn
: (Optional) LSN of the parent branch to create from.parent_timestamp
: (Optional) Timestamp of the parent branch to create from.
protected
attribute is only available for paid plans. It allows you to protect branches from deletion or modification.
For more attributes and options on managing branches, refer to the Provider's documentation.
Managing endpoints
Endpoints provide connection strings to access your branches. Each branch can have multiple read-only endpoints but only one read-write endpoint.
Before creating an endpoint, you must first create a branch for it to connect to. Here's how to create a read-write endpoint for your dev_branch
:
resource "neon_endpoint" "dev_endpoint" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
type = "read_write" # "read_write" or "read_only"
autoscaling_limit_min_cu = 0.25
autoscaling_limit_max_cu = 0.5
# suspend_timeout_seconds = 600
# Optional: Enable connection pooling
# pooler_enabled = true
}
output "dev_endpoint_host" {
value = neon_endpoint.dev_endpoint.host
}
Key neon_endpoint
attributes:
project_id
: (Required) ID of the parent project.branch_id
: (Required) ID of the branch this endpoint connects to.type
: (Optional)read_write
(default) orread_only
. A branch can only have oneread_write
endpoint.autoscaling_limit_min_cu
/autoscaling_limit_max_cu
: (Optional) Compute units for autoscaling.suspend_timeout_seconds
: (Optional) Inactivity period before suspension. Only available for paid plans.pooler_enabled
: (Optional) Enable connection pooling.
note
It is not possible currently to change the endpoint type after creation. The type
attribute is immutable, meaning you cannot modify it once the endpoint is created. This includes changing from read_write
to read_only
or vice versa. This is a limitation of the Neon API and the provider's current implementation. You must destroy the existing endpoint and create a new one with the desired type.
For more attributes and options on managing endpoints, refer to the Provider's documentation
Managing roles
Roles (users) are managed per branch. Before creating a role, ensure you have a branch created. Follow the Managing Branches section for details.
resource "neon_role" "app_user" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "application_user"
}
output "app_user_password" {
value = neon_role.app_user.password
sensitive = true
}
Key neon_role
attributes:
project_id
: (Required) ID of the parent project.branch_id
: (Required) ID of the branch for this role.name
: (Required) Name of the role.password
: (Computed, Sensitive) The generated password for the role.
For more attributes and options on managing roles, refer to the Provider's documentation
Managing databases
Databases are also managed per branch. Follow the Managing Branches section for details on creating a branch.
resource "neon_database" "service_db" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "service_specific_database"
owner_name = neon_role.app_user.name
}
Key neon_database
attributes:
project_id
: (Required) ID of the parent project.branch_id
: (Required) ID of the branch for this database.name
: (Required) Name of the database.owner_name
: (Required) Name of the role that will own this database.
For more attributes and options on managing databases, refer to the Provider's documentation
Managing API keys
You can manage Neon API keys themselves using Terraform.
resource "neon_api_key" "ci_cd_key" {
name = "automation-key-for-ci"
}
output "ci_cd_api_key_value" {
description = "The actual API key token."
value = neon_api_key.ci_cd_key.key
sensitive = true
}
Key neon_api_key
attributes:
name
: (Required) A descriptive name for the API key.key
: (Computed, Sensitive) The generated API key token.
Advanced: Project permissions
Share project access with other users.
resource "neon_project_permission" "share_with_colleague" {
project_id = neon_project.my_app_project.id
grantee = "colleague@example.com"
}
Advanced: JWKS URL for RLS
Configure JWKS URL for Row Level Security authorization.
resource "neon_jwks_url" "auth_provider_jwks" {
project_id = neon_project.my_app_project.id
# Use the default role from the project, or specify custom roles
role_names = [neon_project.my_app_project.database_user]
provider_name = "YourAuthProviderName" # e.g., "clerk"
jwks_url = "<https://<YOUR_AUTH_PROVIDER_JWKS_URL>" # Replace with your actual JWKS URL
}
For a list of supported providers, see Neon RLS: Supported Providers.
For more attributes and options on managing JWKS URLs, refer to the Provider's documentation
Advanced: VPC endpoint management (for Neon private networking)
These resources are used for organizations with Scale or Enterprise plans requiring private networking.
Assign VPC endpoint to organization
resource "neon_vpc_endpoint_assignment" "org_vpc_endpoint" {
org_id = "your-neon-organization-id" # Replace with your actual Org ID
region_id = "aws-us-east-1" # Neon region ID
vpc_endpoint_id = "vpce-xxxxxxxxxxxxxxxxx" # Your AWS VPC Endpoint ID
label = "main-aws-vpc-endpoint"
}
For more attributes and options on managing VPC endpoints, refer to the Provider's documentation
Restrict project to VPC endpoint
resource "neon_vpc_endpoint_restriction" "project_to_vpc" {
project_id = neon_project.my_app_project.id
vpc_endpoint_id = neon_vpc_endpoint_assignment.org_vpc_endpoint.vpc_endpoint_id
label = "restrict-my-app-project-to-vpc"
}
For more attributes and options on managing VPC endpoint restrictions, refer to the Provider's documentation
Apply the configuration
Once you have defined your resources:
-
Format and validate:
terraform fmt terraform validate
-
Plan: Run
terraform plan
to see what actions Terraform will take. This command shows you the resources that will be created, modified, or destroyed without making any changes. Review the output carefully to ensure it matches your expectations.terraform plan -out=tfplan
-
Apply: Run
terraform apply
to create the resources in Neon.terraform apply tfplan
Terraform will ask for confirmation before proceeding with the changes. Type
yes
to confirm.
You have now successfully created and managed Neon resources using Terraform! You can continue to modify your main.tf
file to add, change, or remove resources as needed. After making changes, always run terraform plan
to review the changes before applying them.
Import existing Neon resources
If you have existing Neon resources that were created outside of Terraform (e.g., via the Neon Console or API directly), you can bring them under Terraform's management. This allows you to manage their lifecycle with code moving forward.
Terraform offers two primary ways to do this: using the terraform import
CLI command or, for Terraform 1.5.0
and later, using declarative import
blocks directly in your configuration.
Both methods involve telling Terraform about an existing resource and associating it with a resource block in your configuration.
Set up your Terraform configuration
Before you can import any resources, ensure your Terraform environment is configured for the Neon provider:
-
Define the provider: Make sure you have the
neon
provider declared in yourmain.tf
or a dedicatedproviders.tf
file.terraform { required_providers { neon = { source = "kislerdm/neon" } } } provider "neon" {}
-
Initialize terraform: If you haven't already, or if you've just added the provider configuration, run:
terraform init
This downloads the Neon provider plugin.
Important: Provider Upgrades
Avoid using
terraform init -upgrade
in CI pipelines and auto-approved pull requests, as this can lead to unintended resource replacements and data loss if there are breaking changes or major version jumps. Instead, useterraform init
in your automated workflows. Runningterraform init -upgrade
should always be done manually, followed by plan reviews. For additional guidance, see Important usage notes. -
Configure authentication: Follow the authentication steps mentioned in Configure Authentication to ensure Terraform can communicate with your Neon account.
Neon resource IDs for import
When importing Neon resources, you need to know the specific ID format for each resource type. Always refer to the "Import" section of the specific resource's documentation page on the Provider's GitHub: kislerdm/terraform-provider-neon
for the exact ID format.
Here are some common formats for different Neon resources:
neon_project
: Uses the Project ID (e.g.,damp-recipe-88779456
).neon_branch
: Uses the Branch ID (e.g.,br-orange-bonus-a4v00wjl
).neon_endpoint
: Uses the Endpoint ID (e.g.,ep-blue-cell-a4xzunwf
).neon_role
: Uses a composite ID:<project_id>/<branch_id>/<role_name>
(e.g.,damp-recipe-88779456/br-orange-bonus-a4v00wjl/application_user
).neon_database
: Uses a composite ID:<project_id>/<branch_id>/<database_name>
(e.g.,damp-recipe-88779456/br-orange-bonus-a4v00wjl/service_specific_database
).neon_api_key
andneon_jwks_url
: These resources do not support import. You'll need to recreate them using Terraform if you want to manage them via IaC.
Order of import for dependent resources
When importing resources that depend on each other, it's best practice to import them in the order of their dependencies. This helps ensure that Terraform can correctly understand relationships and that your HCL resource blocks can reference already-imported parent resources.
A common order for importing Neon resources is:
Project -> Branch -> Endpoint -> Role -> Database
Depending on your preference and the version of Terraform you are using, you can choose between two methods to import existing Neon resources into Terraform. Follow Method 1 if you prefer the traditional CLI import command, or Method 2 if you want to use the newer declarative import
blocks introduced in Terraform 1.5.0
.
Method 1: Using the terraform import
CLI command
For each Neon resource you want to import, you'll generally follow these two steps:
-
Write a resource block: Add a corresponding
resource
block to your Terraform configuration files (e.g.,main.tf
). This block tells Terraform how you want the resource to be configured. You might not know all the attributes perfectly upfront; Terraform will populate many of them from the actual state of the resource during the import. -
Run
terraform import
: Execute the import command, which takes the Terraform resource address and the Neon-specific ID of the existing resource.terraform import <terraform_resource_address> <neon_resource_id>
Example: Importing the previously defined resources
In this example, we'll import the resources we defined earlier in the Manage Neon Resources section. This needs a project, a branch, an endpoint, a role, and a database already created in your Neon account. These resources will now be imported into a new Terraform configuration.
Define the HCL resource blocks
In your main.tf
file, define the resource blocks for the existing resources. You can start with minimal definitions, as Terraform will populate the actual values during the import process. You primarily need to define the resource type and a name for Terraform to use. Terraform will populate the actual attribute values from the live resource into its state file during the import. You'll then use terraform plan
to see these and update your HCL to match or to define your desired state.
For required attributes (like project_id
for a branch), you'll either need to hardcode the known ID or reference a resource that will also be imported.
terraform {
required_providers {
neon = {
source = "kislerdm/neon"
}
}
}
provider "neon" {}
# --- Project ---
resource "neon_project" "my_app_project" {}
# --- Development Branch ---
# Requires project_id. We'll reference the project we're about to import.
# The actual value of neon_project.my_app_project.id will be known after its import.
resource "neon_branch" "dev_branch" {
project_id = neon_project.my_app_project.id
name = "feature-x-development"
}
# --- Development Branch Endpoint ---
# Requires project_id and branch_id.
resource "neon_endpoint" "dev_endpoint" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
}
# --- Application User Role on Development Branch ---
# Requires project_id, branch_id, and name.
resource "neon_role" "app_user" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "application_user"
}
# --- Service Database on Development Branch ---
# Requires project_id, branch_id, name, and owner_name.
resource "neon_database" "service_db" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "service_specific_database"
owner_name = neon_role.app_user.name
}
Here's a breakdown of the minimal HCL and why certain attributes are included:
-
neon_project.my_app_project
:- This block defines the Terraform resource for your main Neon project.
- No attributes are strictly required in the HCL for the import command itself, as the project is imported using its unique Neon Project ID. Adding a
name
attribute matching the existing project can aid readability but isn't essential for the import operation.
-
neon_branch.dev_branch
:- This defines the Terraform resource for your development branch.
- It requires
project_id
in the HCL to link it to the (to-be-imported) project resource within Terraform. - The
name
attribute should also be specified in the HCL, matching the existing branch's name, as it's a key identifier. - The branch is imported using its unique Neon Branch ID.
-
neon_endpoint.dev_endpoint
:- This block defines the Terraform resource for the endpoint on your development branch.
- It requires both
project_id
andbranch_id
in the HCL to correctly associate it with the imported project and development branch resources within Terraform. - Other attributes like
type
(which defaults if unspecified) or autoscaling limits will be read from the live resource during import. - The endpoint is imported using its unique Neon Endpoint ID.
-
neon_role.app_user
:- This defines the Terraform resource for an application user role.
- The HCL requires
project_id
andbranch_id
to link to the respective imported Terraform resources. - The
name
attribute must be specified in the HCL and match the existing role's name.
-
neon_database.service_db
:- This defines the Terraform resource for a service-specific database.
- The HCL requires
project_id
andbranch_id
to link to the imported Terraform resources. - The
name
attribute must be specified in the HCL and match the existing database's name. - The
owner_name
should also be included, linking to the Terraform role resource (e.g.,neon_role.app_user.name
) that owns this database.
All other configurable attributes will be populated into Terraform's state file from the live Neon resource during the terraform import
process. You will then refine your HCL by reviewing the terraform plan
output.
Run the import commands in order
-
Import the project:
terraform import neon_project.my_app_project "actual_project_id_from_neon"
You can retrieve the project ID via Neon Console/CLI/API. Learn more: Manage projects
Example output:
terraform import neon_project.my_app_project damp-recipe-88779456
neon_project.my_app_project: Importing from ID "damp-recipe-88779456"... neon_project.my_app_project: Import prepared! Prepared neon_project for import neon_project.my_app_project: Refreshing state... [id=damp-recipe-88779456] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
-
Import the development branch:
terraform import neon_branch.dev_branch "actual_dev_branch_id_from_neon"
You can retrieve the branch ID via Neon Console/CLI/API. Learn more: Manage branches
The following image shows the branch ID in the Neon Console:
Example output:
terraform import neon_branch.dev_branch br-orange-bonus-a4v00wjl
neon_branch.dev_branch: Importing from ID "br-orange-bonus-a4v00wjl"... neon_branch.dev_branch: Import prepared! Prepared neon_branch for import neon_branch.dev_branch: Refreshing state... [id=br-orange-bonus-a4v00wjl] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
-
Import the development compute endpoint:
terraform import neon_endpoint.dev_endpoint "actual_dev_endpoint_id_from_neon"
You can retrieve the endpoint ID via Neon Console/CLI/API. Learn more: Manage computes. The following image shows the endpoint ID in the Neon Console:
Example output:
terraform import neon_endpoint.dev_endpoint ep-blue-cell-a4xzunwf
neon_endpoint.dev_endpoint: Importing from ID "ep-blue-cell-a4xzunwf"... neon_endpoint.dev_endpoint: Import prepared! Prepared neon_endpoint for import neon_endpoint.dev_endpoint: Refreshing state... [id=ep-blue-cell-a4xzunwf] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
-
Import the application user role:
terraform import neon_role.app_user "actual_project_id_from_neon/actual_dev_branch_id_from_neon/application_user"
Replace
application_user
with the actual name of the role you want to import.Example output:
terraform import neon_role.app_user "damp-recipe-88779456/br-orange-bonus-a4v00wjl/application_user"
neon_role.app_user: Importing from ID "damp-recipe-88779456/br-orange-bonus-a4v00wjl/application_user"... neon_role.app_user: Import prepared! Prepared neon_role for import neon_role.app_user: Refreshing state... [id=damp-recipe-88779456/br-orange-bonus-a4v00wjl/application_user] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
-
Import the service database:
terraform import neon_database.service_db "actual_project_id_from_neon/actual_dev_branch_id_from_neon/service_specific_database"
Replace
service_specific_database
with the actual name of the database you want to import.Example output:
terraform import neon_database.service_db "damp-recipe-88779456/br-orange-bonus-a4v00wjl/service_specific_database"
neon_database.service_db: Importing from ID "damp-recipe-88779456/br-orange-bonus-a4v00wjl/service_specific_database"... neon_database.service_db: Import prepared! Prepared neon_database for import neon_database.service_db: Refreshing state... [id=damp-recipe-88779456/br-orange-bonus-a4v00wjl/service_specific_database] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
After importing all resources, your Terraform state file (
terraform.tfstate
) will now contain the imported resources, and you can manage them using Terraform. Follow the Reconcile your HCL with the imported state section to update your HCL files with the attributes that were populated during the import.
Method 2: Using import
Blocks (Terraform 1.5.0+)
Terraform version 1.5.0 and later introduced a more declarative way to import existing infrastructure using import
blocks directly within your configuration files. This method keeps the import definition alongside your resource configuration and makes the import process part of your standard plan
and apply
workflow.
The process with import
Blocks:
For each existing Neon resource you want to bring under Terraform management, you'll define two blocks in your .tf
file:
- A standard
resource "resource_type" "resource_name" {}
block. For the initial import, this block can be minimal. It primarily tells Terraform the type and name of the resource in your configuration. - An
import {}
block:to = resource_type.resource_name
: This refers to the Terraform address of theresource
block you defined above.id = "neon_specific_id"
: This is the actual ID of the resource as it exists in Neon (e.g., project ID, branch ID, or composite ID for roles/databases).
Example using import
blocks:
In this example, we'll import the resources we defined earlier in the Manage Neon Resources section. This needs a project, a branch, an endpoint, a role, and a database already created in your Neon account. These resources will now be imported into a new Terraform configuration. Let's say we have the following existing Neon resources and their IDs:
- Project
my_app_project
ID:damp-recipe-88779456
- Branch
dev_branch
ID:br-orange-bonus-a4v00wjl
- Endpoint
dev_endpoint
ID:ep-blue-cell-a4xzunwf
- Role
application_user
- Database
service_specific_database
You would add the following to your main.tf
:
terraform {
required_providers {
neon = {
source = "kislerdm/neon"
}
}
}
provider "neon" {
# API key configured via environment variable or directly
}
# --- Project Import ---
import {
to = neon_project.my_app_project
id = "damp-recipe-88779456" # Replace with your actual Project ID
}
resource "neon_project" "my_app_project" {
# Minimal definition for import.
# After import and plan, you'll populate this with actual/desired attributes.
}
# --- Development Branch Import ---
import {
to = neon_branch.dev_branch
id = "br-orange-bonus-a4v00wjl" # Replace with your actual Branch ID
}
resource "neon_branch" "dev_branch" {
project_id = neon_project.my_app_project.id # Links to the TF resource
name = "feature-x-development" # Should match existing branch name
}
# --- Development Branch Endpoint Import ---
import {
to = neon_endpoint.dev_endpoint
id = "ep-blue-cell-a4xzunwf" # Replace with your actual Endpoint ID
}
resource "neon_endpoint" "dev_endpoint" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id # Links to the TF resource
}
# --- Application User Role on Development Branch Import ---
import {
to = neon_role.app_user
# ID format: project_id/branch_id/role_name
id = "damp-recipe-88779456/br-orange-bonus-a4v00wjl/application_user"
}
resource "neon_role" "app_user" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "application_user" # Must match existing role name
}
# --- Service Database on Development Branch Import ---
import {
to = neon_database.service_db
# ID format: project_id/branch_id/name
id = "damp-recipe-88779456/br-orange-bonus-a4v00wjl/service_specific_database"
}
resource "neon_database" "service_db" {
project_id = neon_project.my_app_project.id
branch_id = neon_branch.dev_branch.id
name = "service_specific_database" # Must match existing database name
owner_name = neon_role.app_user.name # Links to the TF role resource
}
important
You need to replace the IDs in the import
blocks with the actual IDs of your existing Neon resources. The to
field in each import
block refers to the corresponding resource
block defined in your configuration. The above configuration is a minimal example to get you started with the import process.
Reconcile your HCL with the imported state
After importing your resources using either method, you need to ensure that your HCL configuration accurately reflects the current state of the imported resources. This is an iterative process where you will:
-
Run
terraform plan
:terraform plan
-
Understanding the plan output: The plan might show:
- Attributes to be added to your HCL: Terraform will identify attributes present in the imported state (e.g.,
pg_version
,region_id
,default_endpoint_settings
for a project) that are not yet explicitly in your HCLresource
blocks. - "Update in-place" actions: You might see actions like
~ update in-place
for some resources, even if no actual value in Neon is changing. For example, forneon_endpoint
, you might see+ branch_id = "your-branch-id"
. This is often because Terraform is now resolving a reference (likeneon_branch.dev_branch.id
) to its concrete value and wants to explicitly set this in its managed configuration. It's a reconciliation step and usually safe to apply.
- Attributes to be added to your HCL: Terraform will identify attributes present in the imported state (e.g.,
-
Update your HCL (
main.tf
): Carefully review the output ofterraform plan
. Your primary goal is to update your HCLresource
blocks to accurately match the actual, imported state of your resources, or to define your desired state if you intend to make changes. Copy the relevant attributes and their values from the plan output into your HCL. -
Repeat
terraform plan
: After updating your HCL, runterraform plan
again. Continue this iterative process-reviewing the plan and updating your HCL-untilterraform plan
shows "No changes. Your infrastructure matches the configuration." or only shows changes you intentionally want to make.
This iterative approach ensures your Terraform configuration accurately reflects either the current state or your intended desired state for the imported resources.
Verify and reconcile
Once all attributes are set correctly, you can run terraform plan
to see if any changes are needed. You should be seeing output similar to:
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no
differences, so no changes are needed.
We can now be sure that the resources are managed by Terraform. You can now proceed to make changes to your infrastructure using Terraform.
Destroying resources
To remove the resources managed by Terraform:
terraform destroy
Terraform will ask for confirmation before deleting the resources.
Example application
The following example application demonstrates how to set up Terraform, connect to a Neon Postgres database, and perform a Terraform run that inserts data. It covers how to:
- Use Go's
os/exec
package to run Terraform commands - Write a Go test function to validate Terraform execution
- Execute Terraform commands such as
init
,plan
, andapply
View the YouTube tutorial: Neon Postgres for Terraform with Go.
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more details, see Getting Support.