DevOps

Building a GitHub Organization from Scratch

Austin H.•September 5, 2026•11 min read
#github#devops#organization#teams#governance

Why Organization Structure Matters

Flat repos become unmanageable at scale. GitHub Organizations solve this:

| Problem | Solution | | --------- | ---------- | | 50 repos, can't find anything | Organize by team/product | | Everyone has admin access | Teams enforce roles | | Sensitive secrets leaked | Branch protection + secrets management | | Deployments chaotic | Environments + deployment protection | | No audit trail | Org-level logging |

Setup: Organization Basics

Step 1: Create Organization

Go to GitHub Organizations Settings | New organization

Organization name: my-company
Billing email: billing@company.com
Organization website: [company.com](https://company.com)
Location: San Francisco, CA
Description: Platform engineering and product

Billing: Free tier OK to start. Pay-per-user at scale ($21/user/mo for private repos).

Step 2: Create Teams

Teams map to your internal structure:

my-company/
|--  @maintainers              (org admins)
||    |--  alice (owner)
||    ||--  bob (owner)
|--  @platform-team            (infrastructure)
||    |--  alice
||    |--  charlie
||    ||--  diana
|--  @frontend-team            (product)
||    |--  eve
||    |--  frank
||    ||--  grace
||--  @security-team            (compliance)
    |--  henry
    ||--  iris

Create via CLI

gh org create-team my-company platform-team --description "Infrastructure & DevOps"
gh org create-team my-company frontend-team --description "Frontend & UX"
gh org create-team my-company security-team --description "Security & Compliance"

Add Members

gh org add-member my-company alice --role owner
gh org add-member my-company charlie --role member
gh team add-member platform-team charlie

Step 3: Repository Organization

Name repos with prefixes matching teams:

Infrastructure (platform-team)
|--  infra-k8s              Private, prod-critical
|--  infra-terraform        Private, IaC definitions
|--  infra-monitoring       Private, observability
||--  infra-docs             Public, runbooks

Product (frontend-team)
|--  web                    Private, main SPA
|--  mobile                 Private, React Native
|--  design-system          Public, component library
||--  brand-assets           Private, logos/fonts

Security (security-team)
|--  sec-policies           Private, security policies
|--  sec-audit              Private, audit logs
||--  sec-scanner            Private, automated scanning

Shared
|--  api                    Private, core backend
|--  shared-types           Public, TypeScript interfaces
||--  sdk                    Public, client library

Permission Model

GitHub roles from weakest to strongest:

pull:     Read-only
triage:   Read + label/close issues
push:     Read + write code
maintain: Read + write + manage repo settings
admin:    Full access + sensitive ops (delete, secrets)
Platform Team:
  infra-*:           maintain (manage settings, approvals)
  api:               push (deploy, no settings change)
  shared-types:      push
  
Frontend Team:
  web:               maintain
  mobile:            maintain
  design-system:     maintain
  api:               push (read code, no deploy)
  
Security Team:
  sec-*:             admin (sensitive ops)
  sec-scanner:       admin (secret access)
  api:               push (audit only)

Never grant everyone admin. Start restrictive, grant more access only when needed. Rotating admins reduces single points of failure.

Branch Protection & Enforcement

Protect main Branch

Go to Repo > Settings > Branches > Protect main

# Key settings
Require pull request reviews:
  - Require 2 approvals minimum
  - Dismiss stale reviews when new commits pushed
  - Require code owner reviews (see CODEOWNERS below)
  
Require status checks to pass:
  - Require branches to be up to date before merge
  - Require passing checks:
    - lint
    - test
    - typecheck
    - build
    
Restrict who can push:
  - Include administrators: YES (no force-push shortcuts)
  - Restrict pushes (only admins can push directly)

CODEOWNERS File

Auto-assign reviewers based on path:

# CODEOWNERS
# Infrastructure
/infra/*                @my-company/platform-team
/src/api/auth           @my-company/security-team
/src/api/database       @my-company/platform-team

# Frontend
/src/web/*              @my-company/frontend-team
/src/mobile/*           @my-company/frontend-team

# Shared
/shared-types/*         @my-company/platform-team @my-company/frontend-team
/docs/*                 @my-company/maintainers

Environments & Deployment Protection

Prevent accidental prod deploys:

# .github/workflows/deploy.yml
name: Deploy
on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: [app.company.com](https://app.company.com)
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        run: |
          echo "Deploying to prod..."
          ./deploy.sh
        env:
          DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
          API_KEY: ${{ secrets.PROD_API_KEY }}

Environments require approval from designated reviewers (e.g., platform-team only).

Secrets Management

Store sensitive data at org or repo level:

# Org-level secrets (all repos can access)
gh secret set PROD_DATABASE_URL --body "postgres://..."
gh secret set PROD_API_KEY --body "sk-..."

# Repo-level secrets (this repo only)
gh secret set -R my-org/web STRIPE_SECRET --body "sk-..."

In workflows:

steps:
  - name: Deploy
    env:
      DB_URL: ${{ secrets.PROD_DATABASE_URL }}
      API_KEY: ${{ secrets.PROD_API_KEY }}
    run: npm run deploy

Secret rotation: Change secrets every 90 days. Use a service like Vault for better control.

Org-Level Policies

Require MFA

Settings > Security > Require two-factor authentication

All organization members must enable 2FA.
Non-compliant users lose access until they comply.

IP Allowlist (Enterprise Only)

Restrict access by network:

Only GitHub Actions from:
  - 203.0.113.0/24 (office network)
  - VPN exit nodes
  - GitHub Actions IPs

Audit Logs

Settings > Audit Log > search for suspicious activity

Log everything:
  - Repo creation/deletion
  - Team changes
  - Branch protection updates
  - Secret access
  - Deploy triggers

Export to SIEM:

gh api orgs/my-company/audit-log --paginate > audit.json

Scaling Over Time

Add More Granular Teams

platform-team/
|--  @infra-core      (Kubernetes, networking)
|--  @infra-db        (PostgreSQL, backups)
||--  @infra-security  (IAM, secrets, compliance)

frontend-team/
|--  @web-core        (SPA, routing)
|--  @web-perf        (Performance, bundling)
||--  @mobile          (React Native, iOS/Android)

Distributed Ownership

Each team owns their repos end-to-end:

platform-team deploys:
  - infra-* repos
  - api repo (shared)
  - shared-types repo
  
frontend-team deploys:
  - web repo
  - mobile repo
  - design-system repo
  
No blocking each other.
Each team's CODEOWNERS enforces their standards.

GitHub Projects for Planning

Cross-team visibility without chaos:

Q3 Roadmap (org-level)
|--  Platform: Database migration
|--  Frontend: Mobile app launch
|--  Security: SOC 2 compliance
||--  Shared: Upgrade Node.js 20 → 22

Example: nitsuah Organization

github.com/nitsuah uses this structure:

15+ repos
5 teams (platform, frontend, ai-ml, devops, security)
100+ members
2 environments (staging, production)
All PRs require 2 approvals before merge
Main branch protected, force-push disabled
All secrets stored at org level

Checklist: Day 1

  • [ ] Create organization
  • [ ] Add members
  • [ ] Create teams (platform, frontend, security, ops)
  • [ ] Create repos with prefixes
  • [ ] Set team permissions (push for most, admin for few)
  • [ ] Protect main branch (2 approvals, status checks)
  • [ ] Create CODEOWNERS file
  • [ ] Require MFA for all members
  • [ ] Set audit log export schedule
  • [ ] Create environments (staging, prod)
  • [ ] Document team roles in README.md

Takeaway

GitHub Organizations scale from 5 people to 500. Start with basic teams and repos, add complexity only when needed. The patterns here (CODEOWNERS, branch protection, environment approvals) survive growth |-- they just get refinement, not replacement.

Key Takeaways

  • Organize repos by team/product, not by technology
  • Use teams for permissions, not individual user assignments
  • Branch protection rules prevent force-pushes and require reviews
  • Environments with protection rules gate production deployments
  • CODEOWNERS ensures the right people review the right code

Code References

Creating the Organization

gh org create my-company

Thanks for reading!

Read More Articles