---
url: /salesforce-devops-starter-kit/workflows/deployment.md
description: >-
  Reusable workflow that deploys Salesforce metadata to a target org (sandbox or
  production).
---

# Deployment

Reusable workflow that deploys Salesforce metadata to a target org (sandbox or production). Supports a dry-run (validation only) mode, delta deployments and anonymous Apex post-deploy scripts.

> Reusable workflow - call it from your own repository with `uses:`. [View source](https://github.com/svierk/salesforce-devops-starter-kit/blob/main/.github/workflows/deployment.yml)

## Inputs

| Input | Description | Type | Required | Default |
| --- | --- | --- | --- | --- |
| `source-dir` | Source directory to deploy. | string | no | `force-app` |
| `target-org-alias` | Alias used for the authenticated target org. | string | no | `target-org` |
| `test-level` | Apex test level for the deployment. Ignored when apex-tests is set. | string | no | `RunLocalTests` |
| `apex-tests` | Comma-separated or multi-line list of Apex test classes to run during the deployment. A selection always runs with RunSpecifiedTests. Leave empty to run the test-level. | string | no | - |
| `dry-run` | Validate the deployment without saving the components (check-only). | boolean | no | `false` |
| `delta` | Deploy only the components changed since delta-from. | boolean | no | `false` |
| `delta-from` | Git ref to compare from when delta is enabled, e.g. a previous release tag. | string | no | - |
| `apex-file-path` | Comma-separated anonymous Apex file(s) or glob(s) to execute after a successful deployment, e.g. "./scripts/apex/post-deploy/\*.apex". Skipped on a dry-run. Leave empty to skip. | string | no | - |
| `environment` | Optional GitHub Environment to run in - enables protection rules (required reviewers) and environment-scoped secrets. Leave empty to run without one. | string | no | - |
| `ref` | Optional branch, tag or commit SHA to check out and deploy, e.g. an environment branch for a scheduled full validation, or a release tag. Leave empty to deploy the ref that triggered the workflow. | string | no | - |

## Secrets

| Secret | Description | Required |
| --- | --- | --- |
| `SFDX_CONSUMER_KEY` | Consumer key (client ID) of the connected app used for the JWT flow. | yes |
| `SFDX_JWT_SECRET_KEY` | Contents of the private server key (server.key) used for the JWT flow. | yes |
| `SFDX_USERNAME` | Username of the integration user to authenticate as. | yes |

## Example usage

Copy this caller into your project's `.github/workflows/` directory ([source](https://github.com/svierk/salesforce-devops-starter-kit/blob/main/examples/deployment.yml)):

```yaml
# Example: call the reusable deployment workflow.
# Copy this file into your project's .github/workflows/ directory.

name: Deployment

on:
  push:
    branches: [main]
  workflow_dispatch:

# Least-privilege token: the called workflow only reads the repository and talks
# to Salesforce. A reusable workflow can never get more permissions than the
# caller grants here.
permissions:
  contents: read

jobs:
  deploy:
    uses: svierk/salesforce-devops-starter-kit/.github/workflows/deployment.yml@v1.5.0
    with:
      source-dir: force-app
      target-org-alias: production
      test-level: RunLocalTests
      # Run only a selection of Apex test classes instead (implies RunSpecifiedTests):
      # apex-tests: AccountServiceTest,LeadServiceTest
      dry-run: false
      # Gate this deployment behind a GitHub Environment (required reviewers,
      # environment-scoped secrets). Create it under Settings → Environments and
      # store the production credentials there. Remove to deploy without one.
      environment: production
      # For an incremental deployment of changed components only:
      # delta: true
      # delta-from: <previous release tag or commit>
      # Anonymous Apex post-deploy scripts (data migrations, cache clearing, ...),
      # executed in alphabetical order after a successful, non-dry-run deployment:
      # apex-file-path: ./scripts/apex/post-deploy/*.apex
    secrets:
      SFDX_CONSUMER_KEY: ${{ secrets.SFDX_CONSUMER_KEY }}
      SFDX_JWT_SECRET_KEY: ${{ secrets.SFDX_JWT_SECRET_KEY }}
      SFDX_USERNAME: ${{ secrets.SFDX_USERNAME }}
```
