GitHub Actions CI
Run Apex tests automatically on every push or pull request using the aer GitHub Action. The action installs the aer CLI, runs your test suite, and surfaces failures directly in your workflow logs—no Salesforce org deployment required.
Basic setup
Add a workflow file to your repository at .github/workflows/apex-tests.yml:
name: Apex Tests
on:
pull_request:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run aer tests
uses: octoberswimmer/aer-dist@v1
with:
source: force-app/main/default
env:
AER_LICENSE_KEY: ${{ secrets.AER_LICENSE_KEY }}The AER_LICENSE_KEY secret is required for CI usage. Add it to your repository secrets at Settings > Secrets and variables > Actions > New repository secret. Subscribe at octoberswimmer.com/tools/aer/subscribe to obtain a license key.
Action inputs
Configure the action with these inputs under the with key:
source
Path or paths to your Apex source directories. Pass a single directory:
with:
source: force-app/main/defaultOr multiple directories on separate lines:
with:
source: |
force-app/main/default
force-app-common/main/defaultSpace-separated paths also work:
with:
source: force-app/main/default force-app-common/main/defaultDefaults to . (current directory) if omitted.
flags
Additional arguments passed to aer test. Use this to specify schemas, packages, filters, or any other CLI flags:
with:
source: force-app/main/default
flags: --schema build/schema.gob --package packages/oslog.pkgSkip specific tests with the --skip flag:
with:
source: force-app/main/default
flags: --skip BrokenTest.testMethodversion
Pin the action to a specific aer release:
with:
source: force-app/main/default
version: v0.0.31Defaults to latest, which resolves to the most recent published release. Pinning a version ensures consistent behavior across builds and prevents unexpected failures when new releases ship.
Example workflows
Filter tests by name
Run only tests that match a pattern:
- name: Run integration tests
uses: octoberswimmer/aer-dist@v1
with:
source: force-app/main/default
flags: --filter Integration
env:
AER_LICENSE_KEY: ${{ secrets.AER_LICENSE_KEY }}Matrix strategy for multiple source directories
Test several independent projects in parallel:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
project:
- force-app/main/default
- force-app-common/main/default
- force-app-api/main/default
steps:
- uses: actions/checkout@v4
- name: Run tests for ${{ matrix.project }}
uses: octoberswimmer/aer-dist@v1
with:
source: ${{ matrix.project }}
env:
AER_LICENSE_KEY: ${{ secrets.AER_LICENSE_KEY }}Troubleshooting
License errors
If the workflow fails with a license error, verify that:
- The
AER_LICENSE_KEYsecret exists in your repository settings - The license key is valid and not expired
- The license is a CI license, not a developer license (developer licenses cannot be used in GitHub Actions)
- The secret name in your workflow matches exactly (case-sensitive)
Source directory not found
The action fails if the specified source path does not exist. Common causes:
- Forgetting to run
actions/checkout@v4before the aer action - Specifying the wrong path (check your repository structure)
- Using a relative path from the wrong working directory
Tests fail in CI but pass locally
Check that your CI environment includes all dependencies:
- Package files (
.pkg) must be present if you use--packageor--package-dir - Schema files must exist if you use
--schema - Any bootstrap databases must be generated or checked in before the test step
Run the same aer test command locally with identical flags to reproduce CI behavior.
Related documentation
- Getting Started Guide → – Configure schemas, packages, and data
- Test-Driven Development → – Use watch mode for fast local iteration
- aer test command → – Full CLI reference