Sharing notes from my ongoing learning journey — what I build, break and understand along the way.
My First Infrastructure as Code Experiment on SAP BTP with Terraform
Creating an SAP BTP Subaccount, Cloud Foundry Environment and Space with Terraform
In this post, I used Terraform to perform a small Infrastructure as Code experiment on SAP Business Technology Platform. My goal was not to build a large and complex enterprise setup, but to understand step by step how Terraform works in the context of SAP BTP Administration.
In this lab, I completed the following steps:
1. Logging in with the SAP BTP CLI
2. Creating a Terraform project
3. Using the SAP BTP Terraform provider
4. Creating a new subaccount with Terraform
5. Verifying the created subaccount in the SAP BTP Cockpit
6. Understanding the Terraform state concept
7. Creating a Cloud Foundry environment
8. Adding the Cloud Foundry provider
9. Creating a Cloud Foundry space
This exercise was especially useful for understanding account models, environments, entitlements, Cloud Foundry and Terraform while preparing for SAP BTP Administration topics.
1. Logging in with the SAP BTP CLI
First, I logged in to my global account using the SAP BTP CLI.
In PowerShell, I ran the following command:
btp login
After entering my SAP BTP credentials, the login was successful.
The CLI returned an output similar to this:
Authentication successful
Current target:
global account, subdomain: ...
This step was important because before working with Terraform, I wanted to make sure that my SAP BTP CLI was connected to the correct global account.

2. Preparing the Terraform Project Folder
Next, I created a new Terraform working directory on Windows.
cd C:\
mkdir btp-terraform-lab
cd btp-terraform-lab
Inside this folder, I started creating the Terraform configuration files.
At the beginning, I used three basic files:
providers.tf
variables.tf
terraform.tfvars
The folder structure looked like this:
C:\btp-terraform-lab
├── providers.tf
├── variables.tf
└── terraform.tfvars

3. Defining the SAP BTP Provider
First, I defined the SAP BTP provider in the providers.tf file.
terraform {
required_providers {
btp = {
source = "SAP/btp"
}
}
}
provider "btp" {
globalaccount = var.globalaccount
}
With this file, I told Terraform the following:
This project will use the SAP BTP provider.
The global account information will be taken from a variable.
I did not hardcode the globalaccount value directly into the provider configuration. Instead, I used a variable. This makes the configuration cleaner and easier to reuse.
In the variables.tf file, I defined the variable:
variable "globalaccount" {
description = "SAP BTP Global Account subdomain"
type = string
}
In the terraform.tfvars file, I provided the actual global account subdomain value:
globalaccount = "GLOBAL_ACCOUNT_SUBDOMAIN"
4. Running Terraform Init and Validate
After preparing the files, I ran the following command to initialize Terraform and download the required provider:
terraform init
This command downloaded the SAP BTP provider and prepared the Terraform working directory.
The successful output included the following message:
Terraform has been successfully initialized!
Then I checked whether the configuration was valid:
terraform validate
The result was successful:
Success! The configuration is valid.
At this stage, no resources had been created in SAP BTP yet. I only verified that the Terraform configuration files were written correctly.

5. Planning the First Subaccount with Terraform
Next, I defined the first real resource in the main.tf file: a new SAP BTP subaccount.
resource "btp_subaccount" "tf_sandbox" {
name = "00-eu-core-tf-sandbox"
subdomain = "00-eu-core-tf-sandbox-example"
region = "us10"
}
Here, the following line:
resource "btp_subaccount" "tf_sandbox"
means:
Terraform will manage an SAP BTP subaccount resource.
Inside Terraform, this resource will be named tf_sandbox.
Then I ran the terraform plan command:
terraform plan
Terraform showed me what it was planning to do:
Plan: 1 to add, 0 to change, 0 to destroy.
This output means:
1 new resource will be created.
No existing resources will be changed.
No resources will be destroyed.
At this point, nothing had been created yet. I only reviewed the execution plan.

6. Creating the Subaccount with Terraform Apply
After reviewing the plan, I started the actual creation process:
terraform apply
Terraform showed the plan again and asked for confirmation:
Do you want to perform these actions?
Enter a value:
I confirmed the operation by typing:
yes
After the creation was complete, Terraform returned the following output:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
This means that Terraform successfully created a new subaccount in SAP BTP.

7. Verifying the Subaccount in the SAP BTP Cockpit
After that, I opened the SAP BTP Cockpit and checked whether the new subaccount had actually been created.
Under the global account, the new subaccount was visible:
00-eu-core-tf-sandbox
At this point, the new Terraform-created sandbox subaccount appeared next to the existing manually created DEV / TEST / PROD structure.

When I opened the subaccount, I could also see its general information:
Subdomain
Tenant ID
Subaccount ID
Region
Provider
Environment
Created On
Modified On

8. Checking the Terraform State
To check whether Terraform was tracking the created resource in its state, I ran the following command:
terraform state show btp_subaccount.tf_sandbox
This command showed details of the created subaccount:
name = "00-eu-core-tf-sandbox"
region = "us10"
state = "OK"
subdomain = "..."
With this step, I saw the Terraform state concept in practice.
Terraform state is the structure Terraform uses to track which resources it manages. In other words, Terraform now knows that this subaccount was created and is managed by Terraform.

9. Creating the Cloud Foundry Environment
After the subaccount had been created, the next step was to create a Cloud Foundry environment.
I added a second resource block to the main.tf file:
resource "btp_subaccount_environment_instance" "cloudfoundry" {
subaccount_id = btp_subaccount.tf_sandbox.id
name = "00-eu-core-tf-sandbox"
landscape_label = "cf-us10-001"
environment_type = "cloudfoundry"
service_name = "cloudfoundry"
plan_name = "trial"
parameters = jsonencode({
instance_name = "00-eu-core-tf-sandbox"
})
}
The most important line here was:
subaccount_id = btp_subaccount.tf_sandbox.id
With this line, Terraform created the Cloud Foundry environment inside the subaccount that had just been created by Terraform.
When I ran terraform apply again, Terraform planned to create only the Cloud Foundry environment instance:
Plan: 1 to add, 0 to change, 0 to destroy.
After confirming the operation, it completed successfully:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

10. Verifying the Cloud Foundry Environment in the Cockpit
I then checked the subaccount again in the SAP BTP Cockpit and saw that the Cloud Foundry Environment section had been created.
The following information was visible:
API Endpoint
Org Name
Org ID
Org Memory Limit
At this point, the Cloud Foundry environment had been created successfully.
However, there was one important observation:
Org Memory Limit: 0MB
This means that even though the Cloud Foundry environment had been created, the memory limit still needs to be reviewed before deploying applications.

11. Adding the Cloud Foundry Provider
After creating the Cloud Foundry environment, I wanted to manage resources inside Cloud Foundry, such as spaces.
Here, an important distinction became clear:
SAP BTP Provider:
- Subaccounts
- Environment instances
- Entitlements
- Subscriptions
Cloud Foundry Provider:
- Spaces
- Service instances
- Routes
- Applications
For this reason, I added the Cloud Foundry provider to the providers.tf file:
terraform {
required_providers {
btp = {
source = "SAP/btp"
}
cloudfoundry = {
source = "cloudfoundry/cloudfoundry"
}
}
}
provider "btp" {
globalaccount = var.globalaccount
}
provider "cloudfoundry" {
api_url = "https://api.cf.us10-001.hana.ondemand.com"
}
I took the api_url value directly from the Cloud Foundry Environment screen in the SAP BTP Cockpit.
12. Creating a Cloud Foundry Space
Finally, I created a Cloud Foundry space with Terraform.
I added the following resource block to the main.tf file:
resource "cloudfoundry_space" "tf_dev" {
name = "tf-dev"
org = btp_subaccount_environment_instance.cloudfoundry.platform_id
}
Here:
name = "tf-dev"
defines the name of the space to be created.
The following line:
org = btp_subaccount_environment_instance.cloudfoundry.platform_id
tells Terraform to create this space inside the Cloud Foundry org created through the Cloud Foundry environment instance.
During the first attempt, I received an error related to authorization and the API endpoint. After that, I used the correct values for the Cloud Foundry provider:
CF API URL
CF USER
CF ORIGIN
CF PASSWORD
The origin value was especially important. In the SAP BTP Cockpit, the user origin was shown as sap.ids. Therefore, the Cloud Foundry operation also needed to use the same origin.
After correcting these values, terraform apply completed successfully:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
With this, the tf-dev Cloud Foundry space was created by Terraform.

13. Final Structure of the Terraform Lab
At the end of this exercise, the following structure was created with Terraform:
SAP BTP Global Account
└── Subaccount: 00-eu-core-tf-sandbox
├── Region: us10
├── Cloud Foundry Environment
│ ├── API Endpoint: https://api.cf.us10-001.hana.ondemand.com
│ ├── Org Name: 00-eu-core-tf-sandbox
│ └── Org Memory Limit: 0MB
│
└── Space: tf-dev
The Terraform state now manages the following resources:
btp_subaccount.tf_sandbox
btp_subaccount_environment_instance.cloudfoundry
cloudfoundry_space.tf_dev
14. What I Learned from This Exercise
This practice helped me understand several important SAP BTP Administration and Terraform concepts.
First, I saw the difference between plan and apply in Terraform:
terraform plan
→ Shows what Terraform is going to do.
terraform apply
→ Actually applies the changes.
Second, I saw the Terraform state concept in practice:
terraform state list
→ Lists the resources managed by Terraform.
terraform state show
→ Shows the details of a specific resource.
Third, I learned the difference between the SAP BTP Provider and the Cloud Foundry Provider:
SAP BTP Provider:
Manages BTP-level resources such as subaccounts and environment instances.
Cloud Foundry Provider:
Manages Cloud Foundry resources such as spaces inside an org.
Fourth, I learned that being a BTP administrator is not always enough for Cloud Foundry operations. The correct API endpoint, user, origin and org role are also required.
15. Conclusion
This exercise was my first serious hands-on practice with Terraform in the context of SAP BTP Administration.
In addition to the structures I had previously created manually in the SAP BTP Cockpit, I was now able to create the following resources with Terraform:
Subaccount
Cloud Foundry Environment
Cloud Foundry Space
The next logical steps after this point are:
1. Create a space quota
2. Assign the quota to the space
3. Create a Destination service instance
4. Create a Connectivity service instance
5. Create an XSUAA service instance
6. Make the Terraform code more modular
Although this exercise may look small, it is an important step for SAP BTP platform administration. The setup is no longer only based on manual ClickOps. It is starting to move toward an Infrastructure as Code approach.
