The gcp:organizations/project:Project resource, part of the Pulumi GCP provider, creates and manages GCP projects, which serve as containers for resources, APIs, billing, and IAM policies. This guide focuses on two capabilities: organization and folder placement, and resource manager tags.
Projects must be created under an organization or folder. The executing identity needs roles/resourcemanager.projectCreator permissions on the organization. The examples are intentionally small. Combine them with your own billing accounts, labels, and network configuration.
Create a project under an organization
Most deployments start by creating a project directly under an organization, establishing the top-level container for resources and billing.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const myProject = new gcp.organizations.Project("my_project", {
name: "My Project",
projectId: "your-project-id",
orgId: "1234567",
});
import pulumi
import pulumi_gcp as gcp
my_project = gcp.organizations.Project("my_project",
name="My Project",
project_id="your-project-id",
org_id="1234567")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := organizations.NewProject(ctx, "my_project", &organizations.ProjectArgs{
Name: pulumi.String("My Project"),
ProjectId: pulumi.String("your-project-id"),
OrgId: pulumi.String("1234567"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var myProject = new Gcp.Organizations.Project("my_project", new()
{
Name = "My Project",
ProjectId = "your-project-id",
OrgId = "1234567",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var myProject = new Project("myProject", ProjectArgs.builder()
.name("My Project")
.projectId("your-project-id")
.orgId("1234567")
.build());
}
}
resources:
myProject:
type: gcp:organizations:Project
name: my_project
properties:
name: My Project
projectId: your-project-id
orgId: '1234567'
The projectId must be globally unique across all GCP projects. The orgId places the project at the organization’s top level. The name property sets the human-readable display name shown in the console.
Create a project under a folder
Organizations often group projects into folders to reflect departmental structure or environment boundaries.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const department1 = new gcp.organizations.Folder("department1", {
displayName: "Department 1",
parent: "organizations/1234567",
});
const myProject_in_a_folder = new gcp.organizations.Project("my_project-in-a-folder", {
name: "My Project",
projectId: "your-project-id",
folderId: department1.name,
});
import pulumi
import pulumi_gcp as gcp
department1 = gcp.organizations.Folder("department1",
display_name="Department 1",
parent="organizations/1234567")
my_project_in_a_folder = gcp.organizations.Project("my_project-in-a-folder",
name="My Project",
project_id="your-project-id",
folder_id=department1.name)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
department1, err := organizations.NewFolder(ctx, "department1", &organizations.FolderArgs{
DisplayName: pulumi.String("Department 1"),
Parent: pulumi.String("organizations/1234567"),
})
if err != nil {
return err
}
_, err = organizations.NewProject(ctx, "my_project-in-a-folder", &organizations.ProjectArgs{
Name: pulumi.String("My Project"),
ProjectId: pulumi.String("your-project-id"),
FolderId: department1.Name,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var department1 = new Gcp.Organizations.Folder("department1", new()
{
DisplayName = "Department 1",
Parent = "organizations/1234567",
});
var myProject_in_a_folder = new Gcp.Organizations.Project("my_project-in-a-folder", new()
{
Name = "My Project",
ProjectId = "your-project-id",
FolderId = department1.Name,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Folder;
import com.pulumi.gcp.organizations.FolderArgs;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var department1 = new Folder("department1", FolderArgs.builder()
.displayName("Department 1")
.parent("organizations/1234567")
.build());
var myProject_in_a_folder = new Project("myProject-in-a-folder", ProjectArgs.builder()
.name("My Project")
.projectId("your-project-id")
.folderId(department1.name())
.build());
}
}
resources:
myProject-in-a-folder:
type: gcp:organizations:Project
name: my_project-in-a-folder
properties:
name: My Project
projectId: your-project-id
folderId: ${department1.name}
department1:
type: gcp:organizations:Folder
properties:
displayName: Department 1
parent: organizations/1234567
The folderId property places the project under a specific folder rather than directly under the organization. You can only specify orgId or folderId, not both. The folder’s parent property references the organization, establishing the hierarchy.
Apply resource manager tags at creation
Teams use resource manager tags to enforce policies, track costs, or control access based on environment or ownership.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const myProject = new gcp.organizations.Project("my_project", {
name: "My Project",
projectId: "your-project-id",
orgId: "1234567",
tags: {
"1234567/env": "staging",
},
});
import pulumi
import pulumi_gcp as gcp
my_project = gcp.organizations.Project("my_project",
name="My Project",
project_id="your-project-id",
org_id="1234567",
tags={
"1234567/env": "staging",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := organizations.NewProject(ctx, "my_project", &organizations.ProjectArgs{
Name: pulumi.String("My Project"),
ProjectId: pulumi.String("your-project-id"),
OrgId: pulumi.String("1234567"),
Tags: pulumi.StringMap{
"1234567/env": pulumi.String("staging"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var myProject = new Gcp.Organizations.Project("my_project", new()
{
Name = "My Project",
ProjectId = "your-project-id",
OrgId = "1234567",
Tags =
{
{ "1234567/env", "staging" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.Project;
import com.pulumi.gcp.organizations.ProjectArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var myProject = new Project("myProject", ProjectArgs.builder()
.name("My Project")
.projectId("your-project-id")
.orgId("1234567")
.tags(Map.of("1234567/env", "staging"))
.build());
}
}
resources:
myProject:
type: gcp:organizations:Project
name: my_project
properties:
name: My Project
projectId: your-project-id
orgId: '1234567'
tags:
1234567/env: staging
Resource manager tags follow the format tagKeys/{tag_key_id} for keys and tagValues/{tag_value_id} for values. Tags are immutable after creation; modifying them triggers project recreation. For mutable metadata, use the labels property instead.
Beyond these examples
These snippets focus on specific project-level features: organization and folder placement, and resource manager tags. They’re intentionally minimal rather than full project configurations.
The examples assume pre-existing infrastructure such as a GCP organization with appropriate IAM permissions (roles/resourcemanager.projectCreator), and resource manager tag keys and values for the tagging example. They focus on project creation rather than provisioning the surrounding organization structure.
To keep things focused, common project patterns are omitted, including:
- Billing account attachment (billingAccount)
- Default network control (autoCreateNetwork)
- Labels for metadata (labels vs tags)
- Deletion policies (deletionPolicy: PREVENT, ABANDON, DELETE)
These omissions are intentional: the goal is to illustrate how each project feature is wired, not provide drop-in organization modules. See the GCP Project resource reference for all available configuration options.
Let's create and Manage GCP Projects
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Permissions & Access Control
roles/resourcemanager.projectCreator on the organization, and roles/billing.user on the billing account. The billing account permission is required for every pulumi up and plan operation.roles/billing.user access to the billing account.Project Hierarchy & Organization
orgId to create the project at the organization’s top level, or folderId to create it under a specific folder. Changing either forces project migration.orgId or folderId.Networking & Default Resources
autoCreateNetwork is false; Pulumi just deletes it immediately afterward. You need 1 network slot available. The recommended approach is using the constraints/compute.skipDefaultNetworkCreation organization policy constraint instead.compute.googleapis.com to interact with the GCE API when deleting the default network, and currently leaves it enabled.Immutability & Lifecycle
projectId is immutable. Changing it forces a new project to be created.tags field is immutable and triggers project recreation if modified. To apply tags to existing projects, use the gcp.tags.TagValue resource instead.deletionPolicy to PREVENT (the default). This protects the project from pulumi destroy operations. Other options are ABANDON (removes from state without deleting) and DELETE.Labels & Metadata
labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource, including those set by other clients.Using a different cloud?
Explore integration guides for other cloud providers: