CI/CD Pipelines With GitHub Actions
SkillVeris Team
Cloud & Security Team

GitHub Actions is GitHub's built-in automation platform: you define YAML workflows that run on events like a push or pull request to test, build, and deploy code automatically.
In this guide, you'll learn:
- Workflows live in .github/workflows/, and each contains jobs made of steps that run on GitHub-hosted or self-hosted runners.
- Reusable Actions from the Marketplace handle common tasks like checking out code, setting up languages, and logging into registries.
- The needs keyword chains jobs so deploy only runs after tests and builds pass, creating a gated pipeline.
- Secrets store credentials securely, and environments add approval gates before production deploys.
1What Are GitHub Actions?
GitHub Actions is GitHub's built-in CI/CD and automation platform. You define workflows in YAML that run automatically when events happen in your repository — a push, a pull request, a tag, or a schedule — to test, build, and deploy your code without leaving GitHub.
Because it lives inside the repository, there is no separate server to provision. Commit a workflow file, push it, and GitHub runs your pipeline and shows a green check or red cross next to every commit. It is free for public repositories and includes a monthly minute allowance for private ones.
2The Core Concepts
GitHub Actions has a small vocabulary. Learn these five terms and the YAML stops looking mysterious.
- Workflow: a YAML file in .github/workflows/ that defines an automated process.
- Event: what triggers a workflow — push, pull_request, schedule, or manual dispatch.
- Job: a group of steps that run together on a single runner.
- Step: a single task — either a shell command or a reusable Action.
- Runner: the machine that executes a job, either GitHub-hosted or self-hosted.
🔑Mental Model
A workflow is triggered by an event, contains one or more jobs, and each job runs steps on a runner. That single sentence covers the whole model.
3Your First Workflow
A minimal CI workflow checks out your code, sets up a language, installs dependencies, and runs tests. Save this as .github/workflows/ci.yml and push it.
- name: CI
- on:
- push:
- branches: [main]
- pull_request:
- jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: '20'
- - run: npm ci
- - run: npm test
Reading the File
on defines the triggers, jobs.test.runs-on picks the runner OS, and steps runs in order. Steps that start with uses pull a reusable Action; steps with run execute a shell command. If any step fails, the job stops and the commit is marked failed.
4Using Actions From the Marketplace
You rarely script everything by hand. The GitHub Marketplace hosts thousands of reusable Actions — small packaged tasks — that you reference with uses and configure with a with block.
- actions/checkout@v4 — clone your repository into the runner.
- actions/setup-python@v5 — install a specific Python version.
- actions/cache@v4 — cache dependencies between runs to save time.
- docker/login-action@v3 — authenticate to a container registry.
- docker/build-push-action@v6 — build and push a Docker image.
⚠️Pin Versions
Reference actions by a released version like @v4, never @main. Pulling an unpinned action means an upstream change could run untrusted code in your pipeline — a real supply-chain risk.
5Chaining Jobs Into a Pipeline
By default jobs run in parallel. The needs keyword creates dependencies, turning independent jobs into a gated pipeline where each stage only runs if the previous one passed.
- jobs:
- test: { runs-on: ubuntu-latest, steps: [...] }
- build:
- needs: test # only builds if tests pass
- runs-on: ubuntu-latest
- deploy:
- needs: build # only deploys if the build succeeds
- runs-on: ubuntu-latest
Why Gates Matter
This chaining is what makes a pipeline safe: broken tests stop the build, and a failed build stops the deploy. Nothing untested ever reaches production because each job is a gate the previous stage must clear.
6Secrets and Environments
Deployments need credentials, and hardcoding them in YAML is dangerous. GitHub provides encrypted secrets and protected environments for exactly this.
- Store credentials under repo Settings -> Secrets and reference them as ${{ secrets.NAME }}.
- Secrets are masked in logs and never exposed to workflows from forked pull requests by default.
- Environments (like production) can require a manual approval before a deploy job runs.
- Environment protection rules can also restrict which branches may deploy.
💡Approval Gates
Add environment: production to your deploy job and configure required reviewers. GitHub then pauses the pipeline for a one-click human approval before shipping.
7Best Practices
A few habits keep GitHub Actions pipelines fast, secure, and trusted as your project grows.
- Keep CI under about ten minutes — slow pipelines get ignored or bypassed. Parallelise and cache.
- Cache dependencies with actions/cache to avoid reinstalling packages on every run.
- Use least-privilege permissions with the permissions key rather than the default broad token.
- Pin third-party actions to a version or commit SHA to avoid supply-chain surprises.
- Add status checks as required branch protections so unreviewed, failing code cannot merge.
8Common Mistakes to Avoid
Most GitHub Actions frustration comes from a handful of avoidable errors.
- Hardcoding tokens or passwords in the workflow file instead of using secrets.
- Running everything in one giant job, so a slow deploy blocks fast test feedback.
- Forgetting needs, so a deploy job runs in parallel with tests and ships broken code.
- Leaving actions unpinned at @main and inheriting whatever upstream pushes next.
⚠️Watch Out
A workflow with no test step is just an automated deploy script — it ships bugs faster. Always gate deploys behind a real test job.
9Key Takeaways
The essentials of GitHub Actions come down to a few durable ideas.
- GitHub Actions runs YAML workflows on repository events to automate testing, building, and deploying.
- Workflows contain jobs; jobs contain steps that run commands or reusable Actions on runners.
- The needs keyword chains jobs into a gated pipeline where each stage must pass.
- Store credentials in secrets and use environments for approval gates before production.
- Pin action versions, cache dependencies, and keep pipelines fast and least-privilege.
10Frequently Asked Questions
Q: Is GitHub Actions free? A: It is free with no minute limits for public repositories. Private repositories receive a monthly allowance of free minutes on the free plan, with paid tiers offering more. Check GitHub's pricing page for current figures.
Q: What is the difference between a job and a step? A: A job is a group of steps that runs together on one runner, and jobs can run in parallel or be chained with needs. A step is a single task within a job — either a shell command or a reusable Action.
Q: Can GitHub Actions deploy to any cloud? A: Yes. Using Marketplace actions or plain CLI commands with stored secrets, workflows can deploy to AWS, Azure, Google Cloud, container registries, or your own servers over SSH. It is not limited to GitHub-hosted targets.
Q: How do I keep secrets out of my workflow? A: Store them as encrypted repository or environment secrets and reference them as ${{ secrets.NAME }}. They are masked in logs and are not exposed to workflows triggered by forked pull requests by default.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Cloud & Security Team
Our cloud and security experts break down complex infrastructure topics into practical, beginner-friendly guides.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.