Continuous integration and continuous deployment have gone from nice-to-have to non-negotiable for professional software teams. Yet many organizations still resist adopting CI/CD because of the perceived complexity and cost of tools like Jenkins, CircleCI, or GitLab CI. GitHub Actions changes this equation entirely. It is built directly into GitHub, offers generous free tier minutes, and provides a workflow model that is both powerful and approachable.
At StrikingWeb, we have standardized on GitHub Actions for our client projects. The tight integration with GitHub repositories, the extensive marketplace of pre-built actions, and the YAML-based configuration make it our preferred choice for automating everything from linting to production deployments.
Understanding the GitHub Actions Model
GitHub Actions uses a hierarchy of concepts: workflows, jobs, steps, and actions. Understanding how these pieces fit together is essential before writing your first workflow file.
A workflow is a YAML file stored in .github/workflows/ in your repository. Each workflow responds to specific events — pushes, pull requests, scheduled times, or manual triggers. A workflow contains one or more jobs, which run in parallel by default on separate virtual machines. Each job consists of steps, which are individual commands or actions — reusable units of automation from the marketplace or your own repository.
Your First Workflow
A basic CI workflow that runs tests on every push and pull request looks like this:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: npm test
This simple file accomplishes what would require a dedicated CI server, configuration management, and ongoing maintenance with traditional tools. It runs on GitHub's hosted runners, caches dependencies for fast builds, and reports results directly on pull requests.
Essential Workflow Patterns
Through our work across dozens of projects, we have identified several workflow patterns that we implement on nearly every repository.
Matrix Testing
Matrix builds let you test against multiple versions of languages, operating systems, or dependencies in parallel. This is invaluable for libraries and tools that need to support multiple environments:
strategy:
matrix:
node-version: [16, 18, 20]
os: [ubuntu-latest, windows-latest]
Each combination runs as a separate job, giving you comprehensive compatibility testing without sequential execution. A 3x2 matrix runs six jobs simultaneously rather than taking six times as long.
Conditional Deployment
Production deployments should only happen when specific conditions are met — merges to the main branch, successful tests, and sometimes manual approval. GitHub Actions supports this through job dependencies, environment protection rules, and conditional expressions:
deploy:
needs: [test, lint, build]
if: github.ref == 'refs/heads/main'
environment: production
runs-on: ubuntu-latest
The needs keyword ensures the deploy job only runs after test, lint, and build jobs succeed. The if condition restricts it to the main branch. The environment keyword connects it to GitHub's environment protection rules, which can require manual approvals and restrict which branches can deploy.
Caching and Performance
Build times directly affect developer productivity. GitHub Actions provides several caching mechanisms to avoid redundant work:
- Dependency caching: The
actions/cacheaction stores and restores node_modules, pip packages, or any directory between runs - Setup action caching: Actions like
actions/setup-nodehave built-in cache support that handles dependency caching automatically - Docker layer caching: For Docker builds, caching layers between runs can reduce build times from minutes to seconds
- Artifact sharing: The
actions/upload-artifactandactions/download-artifactactions let you share build outputs between jobs without rebuilding
The GitHub Actions Marketplace
The marketplace is one of GitHub Actions' strongest features. With thousands of pre-built actions, you can add capabilities to your workflows without writing custom scripts.
Actions We Use on Every Project
After evaluating hundreds of marketplace actions, our standard toolkit includes:
- actions/checkout and actions/setup-node: The foundation of every Node.js workflow
- codecov/codecov-action: Uploads test coverage reports for tracking code quality over time
- github/codeql-action: Static analysis for security vulnerabilities, available free for public repositories
- aws-actions/configure-aws-credentials: Secure AWS authentication using OIDC federation rather than stored secrets
- docker/build-push-action: Optimized Docker image building with multi-platform support and layer caching
- peter-evans/create-pull-request: Automates creating PRs from workflow-generated changes, useful for dependency updates
Building Custom Actions
When marketplace actions do not meet your needs, building custom actions is straightforward. Actions can be written in JavaScript (using the @actions/core and @actions/github packages), as Docker containers, or as composite actions that combine multiple steps into a reusable unit.
Composite actions are our preferred approach for team-specific automation. They live in a shared repository and can be referenced across all projects, ensuring consistency in how we run deployments, send notifications, or perform code quality checks.
Deployment Strategies
GitHub Actions supports any deployment target, from simple static site hosting to complex Kubernetes orchestrations. Here are the strategies we implement most frequently.
Static Site Deployment
For static sites built with Next.js, Gatsby, or plain HTML, we deploy directly to AWS S3 with CloudFront invalidation, Vercel, or Netlify. The workflow builds the site, uploads assets, and invalidates the CDN cache — all in under two minutes.
Container Deployment
For containerized applications, the workflow builds a Docker image, pushes it to Amazon ECR or GitHub Container Registry, and triggers a deployment to ECS, EKS, or a similar orchestration platform. We use environment-specific tags and rolling deployments to minimize downtime.
Multi-Environment Pipelines
Production applications need staging environments for testing before release. We structure workflows with separate jobs for each environment, using GitHub environments for approval gates:
A well-designed pipeline deploys to staging automatically on every merge to main, runs integration tests against staging, and then waits for manual approval before promoting to production. This gives your team confidence without sacrificing velocity.
Security Best Practices
CI/CD pipelines have access to your source code, deployment credentials, and production infrastructure. Securing them is critical.
- Use OIDC for cloud authentication: Instead of storing long-lived AWS or GCP credentials as secrets, use OpenID Connect federation for short-lived, automatically rotated tokens
- Pin action versions: Reference actions by commit SHA rather than tags to prevent supply chain attacks through compromised actions
- Limit permissions: Use the
permissionskey to grant workflows only the GitHub token scopes they need - Review third-party actions: Before using a marketplace action, review its source code and check its maintenance status
- Use environment protection rules: Require approvals for production deployments and restrict which branches can trigger them
Cost Optimization
GitHub Actions is free for public repositories and includes 2,000 minutes per month for private repositories on the free plan. For most teams, this is more than sufficient. However, as your usage grows, understanding the billing model helps optimize costs.
Linux runners are the cheapest option at 1x pricing. macOS runners cost 10x and Windows runners cost 2x. If you need macOS for iOS builds, consider running only the platform-specific steps on macOS and handling everything else on Linux. Self-hosted runners eliminate per-minute costs entirely and give you more control over the execution environment.
Getting Started
If your team is not yet using CI/CD, start with a simple test workflow. The immediate feedback loop — seeing test results on every pull request — changes how your team thinks about code quality. From there, add linting, security scanning, and automated deployments incrementally.
At StrikingWeb, we set up GitHub Actions workflows as part of every project engagement. Whether you need a basic CI pipeline or a complex multi-environment deployment strategy, we build pipelines that run reliably and scale with your team. Reach out if you would like us to automate your development workflow.