How to Sync GitHub Teams With Google Groups
SyncMyGroup team · September 10, 2026
GitHub teams do real work. They hold repository permissions, they're the reviewers in CODEOWNERS, and they're what @acme/platform resolves to in a pull request. When team membership drifts, the symptoms are concrete: a new engineer can't push to the repo they were hired to work on, review requests go to someone who moved teams in the spring, and a person who left still has write access to production infrastructure code.
If your company runs on Google Workspace, the people who belong on @acme/platform are probably already listed in platform@acme.com. This post covers how to make the GitHub team follow the Google Group.
What GitHub supports natively (as of 2026)
GitHub has a feature called team synchronization that links a GitHub team to an identity provider group, so membership changes in the IdP flow into the team. Per GitHub's Enterprise Cloud documentation, checked September 2026:
- It's an Enterprise Cloud feature. GitHub lists Enterprise at $21 per user per month and Team at $4 (github.com/pricing, 2026).
- The supported identity providers are Microsoft Entra ID (commercial tenants) and Okta. Google Workspace isn't on the list.
- Entra ID team sync requires SAML single sign-on; Okta team sync requires SAML and SCIM already set up with Okta.
- The GitHub team must already exist before you can connect it to an IdP group. Creating a group in your IdP doesn't create the team.
- Team sync isn't a provisioning tool: in most cases it doesn't invite non-members to the organization.
So if you're on Google Workspace without Okta or Entra in the middle, there's no built-in path from a Google Group to a GitHub team. That's the gap this post is about.
One more native detail worth knowing before you automate anything: once a team is connected to an IdP with team sync, GitHub returns an error if you try to change that team's membership through the REST API. You manage it in the IdP instead. Pick one mechanism per team — never both.
The identity problem comes first
Google Groups contain email addresses. GitHub teams contain GitHub usernames. The join between the two is the hard part of every Google-to-GitHub sync, and it's worth sorting out before you pick a tool.
Common situations:
- Personal GitHub accounts. Most engineers join your org with an account they already had. Its primary email is often personal, and email visibility on GitHub is up to the user.
- Managed or company-created accounts. If people create accounts with their work email, matching is much easier.
- Verified domain emails. Organizations can verify a domain on GitHub, which helps tie accounts to company addresses.
Whatever you choose, keep a reliable mapping from work email to GitHub username. If your sync can't resolve someone, it should log them, not silently skip them. Read the setup notes for your tool of choice — for SyncMyGroup, docs.syncmygroup.com covers connecting GitHub — and test identity matching on a small group first.
Option 1: Terraform
If your GitHub org is already managed with Terraform, team membership can be too. The GitHub provider has github_team and github_team_membership (or github_team_members) resources:
resource "github_team" "platform" {
name = "platform"
privacy = "closed"
}
resource "github_team_members" "platform" {
team_id = github_team.platform.id
dynamic "members" {
for_each = var.platform_usernames
content {
username = members.value
role = "member"
}
}
}
The question is where var.platform_usernames comes from. Either someone edits it in a pull request (reviewable, but manual and slow), or a pre-step reads the Google Group through the Admin SDK Directory API (members.list), maps emails to usernames, and writes the variable file. The second version is a sync job with Terraform on the end.
Terraform's strength here is review: every membership change shows up in a plan. Its weakness is that drift only gets fixed when someone runs apply.
Option 2: A scheduled script
The direct approach: read the Google Group, read the GitHub team, compute the difference, apply it.
# Pseudocode for one Google Group -> GitHub team mapping
google = set(directory.members().list(groupKey="platform@acme.com").execute()...)
wanted = {email_to_login[e] for e in google if e in email_to_login}
current = {m["login"] for m in gh.get(f"/orgs/acme/teams/platform/members")}
for login in wanted - current:
gh.put(f"/orgs/acme/teams/platform/memberships/{login}", json={"role": "member"})
for login in current - wanted - PERMANENT:
gh.delete(f"/orgs/acme/teams/platform/memberships/{login}")
GitHub's REST endpoints are PUT and DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}. Behaviour to plan for, from GitHub's docs:
- Adding someone who isn't an org member sends them an org invitation by email, and their team membership stays pending until they accept. Only org owners can do this. On a paid plan, an accepted invitation is a new seat — decide whether your sync is allowed to grow the org or only manage teams for existing members.
- Removing requires team admin or org owner permissions.
- Teams with IdP team sync reject API membership changes.
Also handle nested Google Groups (the Directory API returns a nested group as a member of type GROUP, so you need to expand it), pagination, and rate limits. Then add alerting for when the job stops running.
Option 3: A purpose-built sync
SyncMyGroup connects Google Workspace and GitHub and keeps a GitHub team matching a Google Group:
- Connect Google Workspace and GitHub at app.syncmygroup.com.
- Create a sync with
platform@acme.comas the source and theplatformteam as the destination. Missing teams can be created in GitHub; teams can also be deleted when their source group goes away. - Nested groups are supported for Google, so
engineering@containingplatform@anddata@flattens into the right GitHub team members. - Filters and exclusions. Skip groups that shouldn't become teams (all-company lists, external-facing aliases) and exclude individual users.
- Permanent users. Keep a security reviewer or a team maintainer in the team regardless of the Google roster.
- Preview. You see every add and remove before anything is written. Recommended actions, built from a diff of your groups, suggest what to sync next.
- Notifications.
@SyncMyGroups subscribe <team>in Slack (or Microsoft Teams) posts each change, which gives you a running record of who gained and lost access to the team's repositories.
Because sync works both ways, you can also run GitHub → Google: build a platform-reviewers@ mailing list from the GitHub team that already owns CODEOWNERS, for instance.
Which direction should be the source of truth?
| Situation | Source | Destination |
|---|---|---|
| HR and IT own team membership in Google Workspace | Google Group | GitHub team |
| Engineering manages teams in GitHub and other tools follow | GitHub team | Google Group, Slack user group |
| Both exist, both get edited | Pick one; see one-way vs two-way group sync |
For most companies, Google is the source for "who is on the platform team" and GitHub follows. Repository permissions stay on the GitHub team; membership comes from Google.
Rollout plan
- Inventory. List GitHub teams with repository access or
CODEOWNERSentries. Those are the ones where drift costs something. - Pair them. Match each team to a Google Group. Teams with no obvious group are a sign that either the team or the group shouldn't exist.
- Fix identities. Make sure every member of the source groups has a resolvable GitHub account.
- Disable other writers. If a team is under IdP team sync, Terraform, or a script, remove that before connecting a new sync.
- Preview one team. Expect removals; review them with the team lead.
- Expand. Then wire the same groups into Slack and Jira so one change in Google moves everything — see Slack ↔ GitHub and GitHub ↔ Jira.
GitLab users have the same problem with a different API; see Sync GitLab groups with Google Groups.
Cost
SyncMyGroup is free up to 5 users across every integration. The Starter plan is $2 per user per month with unlimited users (pricing). Compare that with moving to GitHub Enterprise Cloud plus Okta or Entra purely to get team sync.
FAQ
Can GitHub sync teams with Google Workspace directly?
Not as of 2026. GitHub's team synchronization supports Microsoft Entra ID and Okta on GitHub Enterprise Cloud. Google Workspace users need a script, Terraform pipeline, or a sync tool.
What happens if the sync adds someone who isn't in the GitHub org?
GitHub's API sends them an organization invitation by email, and the team membership stays pending until they accept. On paid plans, that becomes a seat. Decide up front whether your sync may invite people or should only manage existing members.
Can I use team sync and a separate sync tool on the same team?
No. When a team is connected to an IdP through team sync, GitHub rejects API changes to its membership. Use one mechanism per team.
Do nested Google Groups work?
The Directory API returns nested groups as members of type GROUP, so a script has to expand them. SyncMyGroup supports nested Google Groups and flattens them into the destination team.
Want to see the diff for your own teams? Book a walkthrough or browse all supported workflows.