Skip to main content

Quick start

This guide will help you deploy Safe Settings and configure your first repository policies in under 10 minutes.

Prerequisites

Before you begin, ensure you have:
  • Organization admin access: Required to create and install GitHub Apps
  • Admin repository: You’ll create this during setup (default name: admin)
  • Deployment environment: Choose from Docker, AWS Lambda, Kubernetes, or GitHub Actions
1
Create a GitHub App
2
Safe Settings runs as a GitHub App that responds to webhook events in your organization.
4
The manifest flow is the easiest way to create and configure your GitHub App automatically.
5
  • Clone the Safe Settings repository:
    git clone https://github.com/github/safe-settings.git
    cd safe-settings
    
  • Install dependencies:
    npm install
    
  • Create environment configuration:
    cp .env.example .env
    
  • (Optional) Set your organization in .env:
    GH_ORG=your-org-name
    
  • Start the development server:
    npm run dev
    
  • Visit http://localhost:3000 and follow the prompts to create your GitHub App
  • The app will automatically configure permissions and webhook events
  • 6
    Option 2: Manual setup
    7
    If you prefer to create the GitHub App manually:
    8
  • Navigate to GitHub App settings
  • Configure basic information:
    • GitHub App name: safe-settings (or your preferred name)
    • Homepage URL: Your repository or documentation URL
    • Webhook URL: https://your-domain.com/api/github/webhooks
    • Webhook secret: Generate with openssl rand -base64 32
  • Set Repository permissions:
    • Actions: Read-only
    • Administration: Read & Write
    • Checks: Read & Write
    • Commit statuses: Read & Write
    • Contents: Read & Write
    • Custom properties: Read & Write
    • Environments: Read & Write
    • Issues: Read & Write
    • Metadata: Read-only
    • Pull requests: Read & Write
    • Variables: Read & Write
  • Set Organization permissions:
    • Administration: Read & Write
    • Custom properties: Admin
    • Members: Read & Write
  • Subscribe to webhook events:
    • Branch protection rule
    • Check run
    • Check suite
    • Create
    • Custom property values
    • Member
    • Pull request
    • Push
    • Repository
    • Repository ruleset
    • Team
  • Click Create GitHub App
  • Download the private key file
  • Install the app on your organization (click the Install button)
  • 9
    When installing the app, select All repositories to allow Safe Settings to manage all repos in your organization.
    10
    Configure deployment environment
    11
    Safe Settings requires three environment variables to authenticate with GitHub:
    12
    # .env file
    APP_ID=123456
    WEBHOOK_SECRET=your-webhook-secret-from-step-1
    PRIVATE_KEY="$(cat path/to/private-key.pem)"
    # Or use PRIVATE_KEY_PATH instead:
    # PRIVATE_KEY_PATH=/path/to/private-key.pem
    
    13
    PRIVATE_KEY takes precedence over PRIVATE_KEY_PATH. For production, base64-encode the private key and use PRIVATE_KEY.
    14
    Optional environment variables
    15
    # Admin repository name (default: admin)
    ADMIN_REPO=admin
    
    # Configuration path within admin repo (default: .github)
    CONFIG_PATH=.github
    
    # Settings file name (default: settings.yml)
    SETTINGS_FILE_PATH=settings.yml
    
    # Scheduled sync (cron syntax)
    CRON="0 * * * *"  # Run every hour
    
    # Logging level
    LOG_LEVEL=info  # trace, debug, info, warn, error
    
    # Pull request comments (default: true)
    ENABLE_PR_COMMENT=true
    
    # Block manual repo renaming (default: false)
    BLOCK_REPO_RENAME_BY_HUMAN=true
    
    16
    Deploy Safe Settings
    17
    Choose your deployment method:
    18
    Docker
    # Build the container
    docker build -t safe-settings .
    
    # Run with docker-compose (recommended)
    docker-compose --env-file .env up -d
    
    # Or run directly
    docker run -d -p 3000:3000 --env-file .env safe-settings
    
    AWS Lambda
    For production-ready AWS Lambda deployment, use the SafeSettings-Template:
    1. Click “Use this template” on GitHub
    2. Configure AWS credentials in GitHub Secrets
    3. Set environment variables in serverless.yml
    4. Deploy with GitHub Actions
    See the AWS Lambda deployment guide for details.
    Local
    # Development mode with auto-reload
    npm run dev
    
    # Production mode
    npm start
    
    For local development, use smee.io to forward webhooks:
    WEBHOOK_PROXY_URL=https://smee.io/your-unique-url
    
    19
    Create admin repository
    20
    The admin repository stores all your configuration files:
    21
    # Create a private admin repository
    gh repo create your-org/admin --private
    
    # Clone it locally
    gh repo clone your-org/admin
    cd admin
    
    22
    Set up configuration structure
    23
    Create the following directory structure in your admin repository:
    24
    mkdir -p .github/repos .github/suborgs
    
    25
    Your admin repository structure should look like:
    26
    admin/
    ├── .github/
    │   ├── settings.yml          # Organization-wide settings
    │   ├── suborgs/              # Sub-organization configs
    │   │   ├── frontend-team.yml
    │   │   └── backend-team.yml
    │   └── repos/                # Repository-specific configs
    │       ├── api-service.yml
    │       └── web-app.yml
    ├── deployment-settings.yml   # Runtime configuration (optional)
    └── README.md
    
    27
    Create your first configuration
    28
    Create .github/settings.yml with organization-wide defaults:
    29
    # Organization-wide repository defaults
    repository:
      # Make repositories private by default
      private: true
      
      # Enable features
      has_issues: true
      has_projects: true
      has_wiki: false
      
      # Default branch
      default_branch: main
      
      # Auto-delete merged branches
      delete_branch_on_merge: true
      
      # Merge strategies
      allow_squash_merge: true
      allow_merge_commit: true
      allow_rebase_merge: true
    
    # Standard labels for all repositories
    labels:
      - name: bug
        color: CC0000
        description: Something isn't working
      
      - name: enhancement
        color: 336699
        description: New feature or request
      
      - name: documentation
        color: 0075ca
        description: Improvements or additions to documentation
    
    # Branch protection for default branch
    branches:
      - name: default
        protection:
          required_pull_request_reviews:
            required_approving_review_count: 1
            dismiss_stale_reviews: true
            require_code_owner_reviews: true
          
          required_status_checks:
            strict: true
            contexts: []
          
          enforce_admins: false
          
          restrictions: null
    
    30
    Use name: default in branch protection to automatically apply rules to each repository’s default branch (main, master, etc.).
    31
    (Optional) Configure deployment settings
    32
    Create deployment-settings.yml in the admin repository root to restrict which repositories Safe Settings manages:
    33
    # Restrict Safe Settings to specific repositories
    restrictedRepos:
      exclude:
        - admin
        - .github
        - safe-settings
        - test-*
      include:
        - prod-*
        - api-*
    
    # Custom validation rules
    configvalidators:
      - plugin: collaborators
        error: "Admin role cannot be assigned to collaborators"
        script: |
          console.log(`Validating collaborator: ${JSON.stringify(baseconfig)}`)
          return baseconfig.permission !== 'admin'
    
    overridevalidators:
      - plugin: branches
        error: "Branch protection cannot be weakened"
        script: |
          if (baseconfig.protection?.required_pull_request_reviews?.required_approving_review_count && 
              overrideconfig.protection?.required_pull_request_reviews?.required_approving_review_count) {
            return overrideconfig.protection.required_pull_request_reviews.required_approving_review_count >= 
                   baseconfig.protection.required_pull_request_reviews.required_approving_review_count
          }
          return true
    
    34
    Commit and push changes
    35
    Commit your configuration files:
    36
    git add .
    git commit -m "feat: initial Safe Settings configuration"
    git push origin main
    
    37
    Safe Settings only processes changes on the default branch. Changes on other branches are validated in dry-run mode.
    38
    Verify installation
    39
    Safe Settings will automatically:
    40
  • Detect the push event to the admin repository
  • Read configuration files from .github/settings.yml
  • Apply settings to all repositories in your organization
  • Create a check run showing the results
  • 41
    To verify:
    42
  • Navigate to your admin repository on GitHub
  • Click on the latest commit
  • Look for the “Safe-Settings” check run
  • Click “Details” to see what settings were applied
  • What’s next?

    Test with a pull request

    Create a PR with configuration changes to see dry-run validation in action

    Add sub-org configurations

    Create team-specific settings in .github/suborgs/

    Configure specific repositories

    Override settings for individual repos in .github/repos/

    Set up scheduled sync

    Configure CRON environment variable for drift prevention

    Common issues

    Check:
    1. GitHub App is installed with “All repositories” access
    2. Admin repository name matches ADMIN_REPO environment variable (default: admin)
    3. Configuration files are in .github/ directory on the default branch
    4. Repository is not in the restrictedRepos exclude list
    5. Check the Safe-Settings check run for error details
    Check:
    1. Webhook URL is correct in GitHub App settings
    2. Webhook secret matches WEBHOOK_SECRET environment variable
    3. Safe Settings is running and accessible at the webhook URL
    4. Recent deliveries tab in GitHub App settings shows successful deliveries
    Check:
    1. APP_ID matches your GitHub App’s ID
    2. Private key is correctly formatted (include BEGIN/END lines)
    3. PRIVATE_KEY or PRIVATE_KEY_PATH is set correctly
    4. For PRIVATE_KEY, ensure newlines are preserved or base64-encoded
    Remember:
    1. Use name: default to apply to the default branch
    2. All required fields must be present (don’t omit any protection keys)
    3. Set unwanted protections to null explicitly
    4. Status check contexts must exist before adding them

    Next steps

    How It Works

    Learn about the architecture, webhook events, and configuration merging

    Configuration Reference

    Explore all available settings and configuration options

    Build docs developers (and LLMs) love