Manage your entire GitHub organization declaratively using Pulumi and TypeScript.
- Organization settings — default permissions, repo creation policies, webhooks
- Teams & membership — team hierarchy, member roles, team-level repo access
- Repositories — creation, visibility, merge strategies, branch protection rules
- Node.js >= 18 (includes npm)
- Pulumi CLI
- A GitHub personal access token (classic) with admin:org, repo, and delete_repo scopes
# 1. Clone and install
cd github-org-iac
npm install
# 2. Set your GitHub token (never commit this!)
export GITHUB_TOKEN="ghp_your_token_here"
# 3. Set your org name in the stack config
pulumi config set github:owner YOUR_ORG_NAME
# 4. Initialize a Pulumi stack (first time only)
pulumi stack init dev
# 5. Preview changes
pulumi preview
# 6. Apply changes
pulumi up├── Pulumi.yaml # Pulumi project definition
├── Pulumi.dev.yaml # Stack config (org name, etc.)
├── package.json
├── package-lock.json
├── tsconfig.json
└── src/
├── index.ts # Entry point — wires modules together
├── config.ts # YOUR configuration lives here
├── types.ts # TypeScript interfaces
├── organization.ts # Org settings & webhooks
├── teams.ts # Teams, membership, repo access
└── repositories.ts # Repos & branch protection
All configuration lives in src/config.ts. Edit the exported objects to declare your desired state:
export const repositories: Record<string, RepoConfig> = {
"my-new-service": {
description: "A shiny new microservice",
visibility: "private",
topics: ["backend", "typescript"],
branchProtection: {
main: {
requirePullRequestReviews: true,
requiredApprovingReviewCount: 2,
requireStatusChecks: true,
requiredStatusCheckContexts: ["ci/build"],
},
},
},
};export const teams: Record<string, TeamConfig> = {
platform: {
description: "Platform engineering",
members: {
alice: "maintainer",
bob: "member",
},
repositories: {
"my-new-service": "push",
},
},
};export const orgSettings: OrgSettingsConfig = {
defaultRepositoryPermission: "none",
membersCanCreatePublicRepositories: false,
membersCanCreatePrivateRepositories: false,
};If your org already has repos/teams, you can import them into Pulumi state so that future runs manage them without recreating:
# Import an existing repository
pulumi import github:index/repository:Repository repo-my-service my-service
# Import an existing team (use the team's numeric ID)
pulumi import github:index/team:Team team-engineering 123456- Always run
pulumi previewbeforepulumi upto verify changes. - Use a CI pipeline (GitHub Actions, etc.) to run
pulumi upon merge tomainfor GitOps-style management. - Store your Pulumi state in a remote backend (Pulumi Cloud, S3, etc.) for team collaboration.
- The GitHub token needs admin:org scope to manage org settings and teams.