A Step-by-Step Guide to Integrating GitHub with Salesforce

A Step-by-Step Guide to Integrating GitHub with Salesforce
On May 22, 2026, Posted by , In Salesforce

Stop deploying manually. Start shipping with confidence. The complete developer roadmap for connecting Salesforce to GitHub — from zero to automated CI/CD.

Modern software development relies heavily on collaboration, automation, and continuous delivery. While Salesforce provides a powerful platform for building business applications, developers often need robust version control and team collaboration capabilities that go beyond Salesforce’s native tools.

This is where GitHub and Salesforce integration becomes essential.

By integrating GitHub with Salesforce, development teams can manage source code more effectively, automate deployments, improve collaboration, maintain version history, and implement modern DevOps practices.

Whether you’re a Salesforce administrator, developer, architect, or CTO, understanding how to connect Salesforce with GitHub can significantly improve development efficiency and deployment reliability.

In this guide, we’ll explore why GitHub-Salesforce integration matters, the benefits it offers, step-by-step integration methods, best practices, common challenges, and how to build a scalable Salesforce DevOps workflow.

What Is GitHub and Salesforce Integration?

GitHub and Salesforce integration refers to connecting Salesforce development environments with GitHub repositories to manage source code, track changes, automate deployments, and support collaborative development.

Instead of making changes directly in production environments, developers can:

  • Store Salesforce metadata in GitHub
  • Track code changes
  • Collaborate through pull requests
  • Automate deployments
  • Roll back changes when necessary
  • Implement CI/CD pipelines

This approach aligns Salesforce development with modern software engineering practices.

Why Integrate GitHub with Salesforce?

If your Salesforce development team is still using Change Sets to deploy code — copying configurations between orgs one sandbox at a time, without version history, without automated tests, and without any way to review changes before they hit production — you are running a very real risk every single day.

Integrating Salesforce with GitHub transforms your development workflow from a fragile, manual process into a disciplined engineering pipeline. Every change is tracked. Every deployment is reviewed. Every push to production is gated by automated tests. Rollbacks become trivial. Collaboration becomes parallel instead of sequential.

Version Control for Everything
Apex classes, Lightning components, flows, custom objects, permission sets — all tracked in Git with full history, blame, and diff support.

Automated Deployments
Merge to main and a GitHub Action automatically deploys to production. No manual steps, no forgotten configurations, no 2 AM deployments.

Pull Request Reviews
Every change goes through code review before it reaches any org. Your whole team can comment, approve, and catch bugs before they’re deployed.

Parallel Development
Multiple developers work on separate branches simultaneously, each with their own scratch org — no more “whose sandbox is this” confusion.

Read: The Ultimate Guide to Salesforce Integrations – Apps and Tools You Need

How GitHub Fits Into the Salesforce Development Lifecycle

A typical Salesforce development workflow includes:

  • Development in Salesforce Sandbox
  • Source code retrieval
  • Code storage in GitHub
  • Code review via Pull Requests
  • Automated testing
  • Deployment to staging
  • Production deployment

GitHub becomes the single source of truth for Salesforce metadata.

Prerequisites & Tools

Before diving in, make sure you have everything in place. Attempting the integration without these foundations leads to frustrating dead ends.

Tool / AccountWhat it’s forCostRequired?
GitHub AccountHosts your source code and runs GitHub ActionsFreeRequired
Salesforce Developer OrgYour Salesforce environment (Dev Hub enabled)FreeRequired
Node.js (v18+)Runtime for Salesforce CLIFreeRequired
Salesforce CLI (sf)Command-line tool for all Salesforce operationsFreeRequired
VS CodeIDE with Salesforce Extension PackFreeRecommended
Git (v2.30+)Local version control clientFreeRequired
Salesforce Scratch OrgsDisposable dev environments (needs Dev Hub)IncludedRecommended

Developer Edition Org
If you don’t have a Salesforce org, create a free Developer Edition at developer.salesforce.com/signup. You’ll need to enable Dev Hub in Setup → Dev Hub to use scratch orgs, which are essential for the CI/CD pipeline we’re building.

Understanding Salesforce DX (SFDX)

Salesforce DX is the foundation of modern Salesforce development.

It enables:

  • Source-driven development
  • Team collaboration
  • CI/CD automation
  • Version control integration

Salesforce DX converts Salesforce metadata into source files that can be stored and managed in GitHub.

Without Salesforce DX, GitHub integration becomes significantly more difficult.

Also read: Salesforce Integration Strategy for Modern Enterprises

Step 1: Install & Configure Salesforce CLI

The Salesforce CLI (unified as sf) is the foundation of everything. It lets you authenticate to orgs, push and pull source code, run tests, and deploy — all from your terminal and from inside GitHub Actions.

Install the Salesforce CLI

# Install via npm (works on Mac, Windows, Linux)
npm install --global @salesforce/cli

# Verify installation
sf version
# Expected: @salesforce/cli/2.x.x linux-x64 node-v18.x.x

# Install Salesforce Extension Pack in VS Code
# Extensions panel → search "Salesforce Extension Pack" → Install

Authenticate to Your Salesforce Org

Authenticate the CLI to your Salesforce org — both your Developer Hub and your target orgs.


# Authenticate to your Dev Hub org (opens browser)
sf org login web --set-default-dev-hub --alias MyDevHub

# Authenticate to your sandbox
sf org login web --instance-url https://test.salesforce.com --alias MySandbox

# Verify connected orgs
sf org list

# Set your Dev Hub as default
sf config set target-dev-hub=MyDevHub

Pro tip — JWT Auth for CI/CD
The browser-based login is for local development only. For GitHub Actions, you’ll need JWT-based authentication (covered in Step 3) which works headlessly — no browser, no interactive login, just a certificate and a connected app.

Step 2: Set Up Your GitHub Repository

Your GitHub repository is the central source of truth for your Salesforce project. All metadata, Apex code, flows, tests, and pipeline configuration lives here.

Create a New SFDX Project

# Create a new Salesforce DX project
sf project generate --name my-salesforce-project

cd my-salesforce-project

# Initialize Git and push to GitHub
git init
git checkout -b main
gh repo create my-salesforce-project --private --source=. --remote=origin
git add .
git commit -m "chore: initial SFDX project scaffold"
git push -u origin main

Configure Your .gitignore


# Salesforce DX
.sfdx/
.sf/
.localdevserver/

# Node / npm
node_modules/

# Secrets — NEVER commit these
.env
server.key
*.pem

# OS / IDE
.DS_Store
Thumbs.db

Critical — Never commit credentials
Your server.key and any .env files containing org credentials must never be committed to Git. Use GitHub Secrets for all sensitive values. A leaked private key gives full API access to your Salesforce org.

Step 3: Connect Your Salesforce Org to GitHub

Connecting your Salesforce org to GitHub for automated deployments requires a Connected App in Salesforce and JWT-based authentication. This allows GitHub Actions to authenticate headlessly — no browser or interactive login required.

1. Generate a Self-Signed Certificate


# Generate private key and self-signed certificate
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

# server.key = private key → GitHub Secret (NEVER commit to Git)
# server.crt = public cert → upload to Salesforce Connected App

2. Create a Connected App in Salesforce

Navigate to App Manager
In Salesforce Setup, search for App Manager. Click New Connected App in the top right.

Fill in basic information
Name it “GitHub CI/CD”. Add your email as contact. These are identification fields only.

Enable OAuth Settings
Check “Enable OAuth Settings”. Set Callback URL to http://localhost:1717/OauthRedirect. Add scopes: api, refresh_token, and full.

Enable JWT / Digital Signature
Check “Use digital signatures”. Upload server.crt (the public certificate — safe to upload).

Save and copy your Consumer Key
Save the Connected App, then navigate to its detail page and copy the Consumer Key. You’ll add this as a GitHub Secret.

3. Add Secrets to GitHub

Go to your GitHub repo → Settings → Secrets and variables → Actions and add:

Secret NameValue
SALESFORCE_JWT_SECRET_KEYContents of server.key file
SALESFORCE_CONSUMER_KEYConsumer Key value
SALESFORCE_USERNAMEYour Salesforce login username
SALESFORCE_INSTANCE_URLe.g. https://mycompany.my.salesforce.com

Check out: Salesforce Integration Companies vs. In-House Teams

Step 4: Structure Your SFDX Project Correctly

A well-structured SFDX project organises Salesforce metadata in a way that Git can track meaningfully — one file per component, human-readable and diffable.

my-salesforce-project/ ├── .github/workflows/ │ ├── ci.yml # PR validation pipeline │ └── deploy.yml # Production deploy pipeline ├── force-app/main/default/ │ ├── classes/ # Apex classes (.cls + -meta.xml) │ ├── lwc/ # Lightning Web Components │ ├── flows/ # Flow definitions │ ├── objects/ # Custom objects and fields │ ├── permissionsets/ # Permission sets │ └── triggers/ # Apex triggers ├── config/ │ └── project-scratch-def.json ├── sfdx-project.json ├── .forceignore ├── .gitignore └── README.md

Configure sfdx-project.json

{
"packageDirectories": [
{
"path": "force-app",
"default": true,
"package": "MySalesforceApp",
"versionNumber": "1.0.0.NEXT"
}
],
"name": "my-salesforce-project",
"namespace": "",
"sourceApiVersion": "61.0",
"sfdcLoginUrl": "https://login.salesforce.com"
}

Step 5: Working with Scratch Orgs

Scratch orgs are disposable, fully configured Salesforce environments that spin up in seconds. Each developer works in their own scratch org — no more stepping on each other’s configurations in a shared sandbox.

# Create a scratch org (valid for 7 days)
sf org create scratch \
--definition-file config/project-scratch-def.json \
--alias feature-my-feature \
--duration-days 7 \
--set-default

# Push your source to the scratch org
sf project deploy start --target-org feature-my-feature

# Open the scratch org in a browser
sf org open --target-org feature-my-feature

# Pull changes made in the org back to local files
sf project retrieve start --target-org feature-my-feature

# Delete scratch org when done
sf org delete scratch --target-org feature-my-feature --no-prompt

Also check: How to Build a CI/CD Pipeline – Step-by-Step Guide

Step 6: Build Your GitHub Actions CI/CD Pipeline

Two workflows cover the full lifecycle: one validates pull requests, one deploys on merge to main.

Workflow 1: PR Validation (ci.yml)

name: Salesforce CI — Pull Request Validation

on:
pull_request:
branches: [ main, staging ]

jobs:
validate:
runs-on: ubuntu-latest
steps:

- name: Checkout source
uses: actions/checkout@v4

- name: Install Salesforce CLI
run: npm install --global @salesforce/cli

- name: Authenticate to Dev Hub via JWT
run: |
echo "${{ secrets.SALESFORCE_JWT_SECRET_KEY }}" > server.key
sf org login jwt \
--client-id "${{ secrets.SALESFORCE_CONSUMER_KEY }}" \
--jwt-key-file server.key \
--username "${{ secrets.SALESFORCE_USERNAME }}" \
--instance-url "${{ secrets.SALESFORCE_INSTANCE_URL }}" \
--alias DevHub \
--set-default-dev-hub

- name: Create scratch org
run: |
sf org create scratch \
--definition-file config/project-scratch-def.json \
--alias ci-scratch \
--duration-days 1 \
--set-default

- name: Deploy source to scratch org
run: |
sf project deploy start \
--target-org ci-scratch \
--ignore-conflicts

- name: Run Apex tests
run: |
sf apex run test \
--target-org ci-scratch \
--test-level RunLocalTests \
--output-dir test-results \
--result-format junit \
--wait 20

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: apex-test-results
path: test-results/

- name: Delete scratch org
if: always()
run: sf org delete scratch --target-org ci-scratch --no-prompt

Workflow 2: Production Deploy (deploy.yml)

name: Salesforce Deploy — Production

on:
push:
branches: [ main ]

jobs:
deploy-production:
runs-on: ubuntu-latest
environment: production
steps:

- name: Checkout source
uses: actions/checkout@v4

- name: Install Salesforce CLI
run: npm install --global @salesforce/cli

- name: Authenticate to Production Org
run: |
echo "${{ secrets.PROD_JWT_SECRET_KEY }}" > server.key
sf org login jwt \
--client-id "${{ secrets.PROD_CONSUMER_KEY }}" \
--jwt-key-file server.key \
--username "${{ secrets.PROD_USERNAME }}" \
--instance-url https://login.salesforce.com \
--alias Production

- name: Validate deployment first (dry run)
run: |
sf project deploy validate \
--target-org Production \
--test-level RunLocalTests \
--wait 30

- name: Deploy to Production
run: |
sf project deploy start \
--target-org Production \
--test-level RunLocalTests \
--wait 30

Protect your main branch
GitHub → Settings → Branches → Add rule for main: require pull request reviews, require CI status checks to pass, and enable “Require linear history”. This makes it impossible to push directly to production — every change must go through the full pipeline.

Also check: How to Integrate Gmail with Salesforce (Step-by-Step Guide)

Step 7: Automated Testing in the Pipeline

Salesforce requires 75% code coverage to deploy to production. But aiming for the minimum is the wrong goal — good test coverage is what catches regressions before they reach customers.

Writing a Basic Apex Test Class

@isTest
public class AccountServiceTest {

@testSetup
static void setup() {
Account acc = new Account(Name = 'Test Account', Industry = 'Technology');
insert acc;
}

@isTest
static void testAccountCreation() {
Test.startTest();
Account acc = [SELECT Id, Name FROM Account LIMIT 1];
System.assertEquals('Test Account', acc.Name, 'Name should match');
Test.stopTest();
}

@isTest
static void testBulkOperation() {
// Always test bulk scenarios — governor limits apply
List accounts = new List();
for (Integer i = 0; i < 200; i++) { accounts.add(new Account(Name = 'Bulk Account ' + i)); } Test.startTest(); insert accounts; Test.stopTest(); System.assertEquals(200, [SELECT COUNT() FROM Account WHERE Name LIKE 'Bulk%']); } }

Test Level Reference
RunLocalTests runs all tests not from managed packages — right for production. RunSpecifiedTests runs only named test classes — faster for PR validation. RunAllTestsInOrg includes managed package tests — rarely needed.

Step 8: Deploy to Staging & Production

A production-ready pipeline deploys in stages: feature → staging sandbox → UAT → production. Use sf project deploy validate for a dry-run before any production deployment.

# Validate against production (no changes applied)
sf project deploy validate \
--target-org Production \
--test-level RunLocalTests \
--wait 30

# Quick-deploy the validated package (skips re-running tests)
sf project deploy quick \
--use-most-recent \
--target-org Production

# Check deploy status
sf project deploy report --target-org Production

# Cancel if something went wrong
sf project deploy cancel --use-most-recent --target-org Production

Step 9: Branch Strategy for Salesforce Teams

A clear branch strategy separates functional integrations from chaotic ones. The recommended model for Salesforce teams is simplified Gitflow — structured enough for release management, simple enough to actually follow.

BranchPurposeDeploys toProtected?
mainProduction-ready code at all timesProduction orgYes — PR required
stagingPre-production integration & UATFull SandboxYes — PR required
developDaily integration branchDeveloper SandboxOptional
feature/[name]Individual feature workScratch OrgNo
hotfix/[name]Emergency production fixesProduction (after review)PR required

Naming convention
Use descriptive, consistent branch names: feature/W-1234-lead-routing-automation, bugfix/W-1256-opportunity-trigger, hotfix/W-1270-approval-null-pointer. This makes PR history readable without needing to open Jira to understand what a branch does.

Troubleshooting Common Issues

Error / SymptomLikely CauseFix
JWT auth fails in ActionsConnected App not approved or username mismatchProfile → Connected App → "Manage Policies" → set to "Admin approved" and pre-authorise the user
INVALID_SESSION_IDWrong instance URL or expired credentialsVerify SALESFORCE_INSTANCE_URL secret matches your org URL exactly (no trailing slash)
Scratch org creation failsDev Hub not enabled, or daily limit reachedSetup → Dev Hub → Enable. Check active scratch org count with sf org list --all
Deploy fails — missing metadataComponents in org not tracked in sourceRun sf project retrieve start --manifest package.xml to pull all org metadata
Test coverage below 75%Insufficient Apex test classesRun sf apex run test --code-coverage locally to see per-class coverage before pushing
Workflow not triggeringYAML indentation error or wrong branch nameUse a YAML linter. Check branch names in on.push.branches match exactly

Best Practices for GitHub and Salesforce Integration

Use Salesforce DX

Avoid legacy Change Sets whenever possible.

Keep Metadata Modular

Store components logically.

Avoid massive deployments.

Use Branch Protection

Protect:
main
from direct commits.
Require pull request approvals.

Automate Testing

Run:

  • Apex tests
  • Static code analysis
  • Security checks

before deployments.

Maintain Documentation

Document:

  • Branching strategy
  • Deployment process
  • Rollback procedures

Read: How SAP + Salesforce Integration Transforms Your Pipeline

Common Challenges and Solutions

Metadata Conflicts

Problem:

Multiple developers modify the same component.

Solution:

Use feature branches and frequent merges.

Deployment Failures

Problem:

Missing dependencies.

Solution:

Validate deployments before production.

Profile Complexity

Problem:

Profiles create merge conflicts.

Solution:
Use Permission Sets wherever possible.

Large Metadata Repositories

Problem:

Slow repository performance.

Solution:

Modularize metadata and use package-based development.

GitHub Integration vs Salesforce Change Sets

FeatureGitHub IntegrationChange Sets
Version ControlYesNo
CollaborationExcellentLimited
Rollback SupportYesLimited
CI/CD SupportYesNo
Code ReviewsYesNo
AutomationExtensiveMinimal
ScalabilityHighModerate

GitHub provides a significantly more scalable approach.

Security Considerations

When integrating GitHub and Salesforce:

Use Secrets Management

Never store:

  • Passwords
  • Tokens
  • Certificates

inside repositories.

Use GitHub Secrets.

Enable Multi-Factor Authentication

Protect:

  • GitHub accounts
  • Salesforce accounts

Restrict Repository Access

Use least-privilege access principles.

Frequently Asked Questions

Why integrate GitHub with Salesforce?

GitHub provides version control, collaboration, automation, and DevOps capabilities that improve Salesforce development workflows.

Do I need Salesforce DX?

Yes. Salesforce DX is the recommended framework for integrating Salesforce with GitHub.

Can GitHub automate Salesforce deployments?

Yes. GitHub Actions can automate validation, testing, and deployments.

Is GitHub better than Change Sets?

For modern development teams, GitHub offers significantly more flexibility, scalability, and automation than Change Sets.

What is the best branching strategy for Salesforce projects?

Most teams use:

  • Main
  • Develop
  • Feature branches

combined with Pull Requests and code reviews.

Conclusion

Integrating GitHub with Salesforce is no longer just a best practice—it's becoming a necessity for modern Salesforce development teams.

By combining Salesforce DX, GitHub repositories, branching strategies, pull requests, and CI/CD automation, organizations can improve collaboration, reduce deployment risks, accelerate development cycles, and maintain higher code quality.

Whether you're managing a small Salesforce implementation or a large enterprise environment, GitHub integration provides the foundation for scalable, efficient, and future-ready Salesforce DevOps.

Organizations that embrace GitHub-based Salesforce development gain better visibility, stronger governance, faster releases, and a more reliable path from development to production.

Contact Us
A seasoned Salesforce Consultant, Architect, and AI Specialist with 16+ years of experience, helping organizations design, implement, and scale Salesforce solutions across Sales, Service, Experience, and Marketing Clouds. With deep expertise in development, integrations, AI (Agentforce), and AppExchange products, he has successfully partnered with startups and Fortune 500 companies to deliver high-impact Salesforce solutions.

Leave a Reply

Your email address will not be published. Required fields are marked *