Testing GitHub Actions Workflows Locally with act¶
This guide shows you how to test GitHub Actions workflows locally using act, dramatically speeding up workflow development and debugging.
What is act?¶
act is an open-source tool (by nektos) that runs your GitHub Actions workflows locally using Docker. Instead of pushing code to GitHub and waiting for Actions to run, you can test workflows on your machine in seconds.
Benefits¶
- Speed: Test workflows in 5-20 seconds vs 2-5 minutes on GitHub
- Cost: Save GitHub Actions minutes (especially on private repos)
- Iteration: Debug faster without polluting git history
- Offline: Test without internet connection (after images downloaded)
Limitations¶
- Some GitHub-specific features may not work perfectly
- Requires Docker installed and running
- Large workflows may be slow on first run (image pull)
Installation¶
Linux/macOS¶
curl --proto '=https' --tlsv1.2 -sSf \
https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
macOS (Homebrew)¶
Windows (Chocolatey)¶
Verify Installation¶
Configuration¶
First Run Setup¶
On first run, act will ask you to choose a Docker image size:
? Please choose the default image you want to use with act:
- Large size image: +17GB Docker image, includes almost all tools
- Medium size image: ~500MB, includes only necessary tools ← Recommended
- Micro size image: <200MB, contains only NodeJS required to bootstrap
Recommendation: Choose Medium image for balance of features and size.
Configuration File¶
Create .actrc in your project root:
# .actrc
# Use medium-sized image
-P ubuntu-latest=catthehacker/ubuntu:act-latest
# Specify GitHub token for private repos
-s GITHUB_TOKEN=<your-token>
# Specify AWS credentials for Lambda testing
-s AWS_ACCESS_KEY_ID=<your-access-key>
-s AWS_SECRET_ACCESS_KEY=<your-secret-key>
# Use specific platforms
--container-architecture linux/amd64
# Verbose output for debugging
-v
Secrets File¶
Create .secrets file (add to .gitignore!):
# .secrets
GITHUB_TOKEN=ghp_your_token_here
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
GITOPS_PAT=ghp_another_token_here
SYRF_GITHUB_APP_ID=123456
SYRF_GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
Important: Add .secrets and .actrc to .gitignore:
Basic Usage¶
List Available Workflows¶
# List all workflows
act -l
# Example output:
# Stage Job ID Job name Workflow name Workflow file
# 0 detect-changes Detect Changed... CI/CD Pipeline ci-cd-refactored.yml
# 1 version Version Services CI/CD Pipeline ci-cd-refactored.yml
# 2 build-docker Build Docker... CI/CD Pipeline ci-cd-refactored.yml
Run Specific Workflow¶
# Run default trigger (usually 'push')
act
# Run specific event
act push
act pull_request
act workflow_dispatch
# Run specific workflow file
act -W .github/workflows/test-ci-cd.yml
# Run specific job
act -j detect-changes
act -j version
act -j build-docker
Dry Run (See What Would Run)¶
Testing Our Refactored Workflow¶
Test Change Detection¶
# Test detect-changes job only
act push -j detect-changes
# With specific file changes (simulated)
act push -j detect-changes \
--env GITHUB_EVENT_PATH=<(echo '{"commits":[{"modified":["src/services/api/README.md"]}]}')
Test Version Calculation¶
# Test version job (requires GitVersion)
act push -j version
# Note: May fail if GitVersion not in Docker image
# Solution: Use larger image or custom Dockerfile
Test Single Service Build¶
Test with Specific Inputs¶
For workflow_dispatch workflows:
# Test with specific scenario
act workflow_dispatch \
-W .github/workflows/test-ci-cd.yml \
--input test_scenario=single-service-api \
--input simulate_build_failure=none
Test Reusable Workflows¶
Reusable workflows are tricky in act. Best approach:
# Create a test caller workflow
cat > .github/workflows/test-reusable.yml << 'EOF'
name: Test Reusable
on: push
jobs:
test:
uses: ./.github/workflows/reusable-gitversion.yml
with:
service_name: api
config_path: src/services/api/GitVersion.yml
EOF
# Run it
act push -W .github/workflows/test-reusable.yml
# Clean up
rm .github/workflows/test-reusable.yml
Advanced Usage¶
Use Custom Docker Image¶
If you need specific tools (GitVersion, AWS CLI, etc.):
# .act/Dockerfile
FROM catthehacker/ubuntu:act-latest
# Install GitVersion
RUN curl -sL https://github.com/GitTools/GitVersion/releases/download/6.0.0/gitversion-linux-x64-6.0.0.tar.gz | tar xz -C /usr/local/bin
RUN chmod +x /usr/local/bin/gitversion
# Install AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&& ./aws/install \
&& rm -rf awscliv2.zip aws
Build and use:
Environment Variables¶
# Set environment variables
act push \
--env MY_VAR=value \
--env ANOTHER_VAR=another_value
# Load from file
act push --env-file .env.test
Bind Volumes¶
Debug Failed Workflows¶
# Verbose output
act push -v
# Very verbose (includes Docker commands)
act push -vv
# Even more verbose
act push -vvv
Interactive Debugging¶
# Drop into shell on failure
act push --shell
# Manually execute steps in the container
docker exec -it <container-id> bash
Workflow-Specific Testing¶
Test Change Detection Logic¶
Create test event files:
# Test API change
cat > /tmp/api-change.json << EOF
{
"commits": [
{
"added": [],
"modified": ["src/services/api/SyRF.API.Endpoint/Program.cs"],
"removed": []
}
]
}
EOF
act push -j detect-changes \
--eventpath /tmp/api-change.json
Test Matrix Builds¶
# Test matrix expansion
act push -j build-docker -n
# See what combinations would run
act push -j build-docker --matrix service:api
act push -j build-docker --matrix service:pm
Test Conditional Logic¶
# Test with specific conditions
act push -j promote-to-staging \
--env needs.build-docker.outputs.api_success=true \
--env needs.build-docker.outputs.pm_success=false
Troubleshooting¶
Issue: "DOCKER_HOST not set"¶
Solution:
# Linux
export DOCKER_HOST=unix:///var/run/docker.sock
# macOS
export DOCKER_HOST=unix://$HOME/.docker/run/docker.sock
Issue: "Permission denied" errors¶
Solution:
Issue: Workflow uses GitHub-specific features¶
Solution: Use --matrix or --job to run only testable parts:
# Skip jobs that require GitHub features
act push -j detect-changes -j version
# Or use event files to mock GitHub context
Issue: Secrets not working¶
Solution: Verify secrets file:
Issue: Workflow too slow¶
Solution:
- Use smaller Docker images
- Run specific jobs only
- Cache Docker layers
- Use local Docker registry
Best Practices¶
1. Use .actrc for Configuration¶
Don't pass flags every time:
2. Test Incrementally¶
Don't run entire workflow every time:
3. Use Dry Run First¶
Always check what will run:
4. Mock External Dependencies¶
For jobs that call external APIs:
# Create mock responses
act push -j deploy-lambda \
--env AWS_DEFAULT_REGION=eu-west-1 \
--bind /tmp/mock-aws:/root/.aws
5. Clean Up After Testing¶
# Remove stopped containers
docker ps -a --filter "name=act-" --filter "status=exited" -q | xargs docker rm
# Remove dangling images
docker image prune -f
Integration with Development Workflow¶
Pre-Push Hook¶
Add to .git/hooks/pre-push:
#!/bin/bash
echo "Testing workflows locally before push..."
# Test validation
if ! act -W .github/workflows/validate-workflows.yml; then
echo "❌ Workflow validation failed"
exit 1
fi
echo "✅ Workflow validation passed"
VS Code Task¶
Add to .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "Act: Test Workflows",
"type": "shell",
"command": "act push -n",
"group": "test",
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "Act: Run Change Detection",
"type": "shell",
"command": "act push -j detect-changes",
"group": "test"
}
]
}
Makefile¶
Add to Makefile:
.PHONY: test-workflows
test-workflows:
@echo "Testing workflows with act..."
act push -n
.PHONY: test-detect-changes
test-detect-changes:
act push -j detect-changes
.PHONY: test-version
test-version:
act push -j version
Comparison: act vs GitHub Actions¶
| Feature | act (Local) | GitHub Actions |
|---|---|---|
| Speed | 5-20 seconds | 2-5 minutes |
| Cost | Free (local compute) | Limited minutes/month |
| Network | Can work offline | Requires internet |
| Accuracy | ~90% compatible | 100% accurate |
| Debugging | Interactive shell access | Log-based only |
| Secrets | Local file | GitHub Secrets |
| Cache | Docker cache | GitHub cache |
| Parallelization | Limited by local resources | GitHub infrastructure |
When to Use act vs GitHub¶
Use act for¶
- ✅ Rapid iteration during development
- ✅ Syntax checking and validation
- ✅ Testing workflow logic
- ✅ Debugging complex workflows
- ✅ Pre-push verification
Use GitHub Actions for¶
- ✅ Final validation before merge
- ✅ Production deployments
- ✅ Integration with GitHub features
- ✅ Testing on different OS/architectures
- ✅ Long-running workflows
Resources¶
Next Steps¶
- Install act on your development machine
- Create
.actrcand.secretsfiles - Test the refactored workflow locally
- Integrate act into your development workflow
- Share act setup with team members