April 29, 2025
#2: GitHub Actions Tutorial: Getting Started with CI/CD Automation

Photo by Roman Synkevych on Unsplash
Welcome to Part 1 of our comprehensive 3-part GitHub Actions course series. In this first installment, we'll cover the fundamental concepts of GitHub Actions including workflow setup, YAML syntax, triggers, jobs, steps, and using community actions. This foundation will prepare you for the more advanced topics in the later parts of the series, giving you the essential knowledge needed to start implementing automation in your GitHub repositories.
What is GitHub Actions?
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline directly within your GitHub repository. It enables you to create workflows that can build and test every pull request to your repository or deploy merged pull requests to production.
Why use GitHub Actions?
Automation: GitHub Actions allows you to automate tasks within your GitHub repository, such as running tests, building software, and deploying applications.
CI/CD: It facilitates continuous integration and continuous delivery, enabling you to automatically build, test, and deploy your code whenever changes are made.
Workflow Definition: You define workflows using YAML files, specifying the steps and actions to be performed.
Event Triggering: Workflows can be triggered by various events, such as code pushes, pull requests, or scheduled intervals.
Customization: You can create custom workflows and actions to meet your specific needs, according to the GitHub Docs.
Reusable Actions: You can use pre-written actions from the GitHub Marketplace or create your own to perform common tasks. For instance, a team uses a shared internal GitHub Action to standardize how all microservices are linted, tested, and pushed to Docker Hub.
Testing: GitHub Actions allows you to run tests across multiple platforms and environments, ensuring that your code works as expected. For example, a React app runs Jest unit tests, checks code formatting with Prettier, and tests on both Node 16 and 18 to catch version-specific bugs.
Deployment: You can use GitHub Actions to automatically deploy your code to various platforms and environments, streamlining the deployment process. Like this blog, A Next.js blog automatically deploys to Vercel when changes are pushed to the main branch, and sends a Slack alert on success.
Core Concepts
The GitHub Actions Ecosystem
GitHub Actions is built around several key components:
- Workflows: Automated procedures defined in YAML files in your repository
- Events: Triggers that start a workflow (e.g., push, pull request)
- Jobs: Groups of steps that execute on the same runner
- Steps: Individual tasks within a job that can run commands or actions
- Actions: Reusable units of code that perform a specific task
- Runners: The servers that execute your workflows
How GitHub Actions Works
- An event occurs in your repository (e.g., a push to the main branch)
- This event triggers a workflow defined in your repository
- The workflow consists of one or more jobs
- Each job runs on a specified runner (virtual environment)
- The steps within each job execute sequentially
- The workflow completes, and you can view the results
Directory Structure
GitHub Actions workflows are stored in the .github/workflows directory in your repository. Each workflow is defined in a separate YAML file.
repository-root/
├── .github/
│ └── workflows/
│ ├── hello-world.yml
│ └── deploy.yml
├── src/
└── ...
Setting Up Your First Workflow
Creating Your First Workflow File
At this point I assume you have a GitHub account and basic understanding of git commands, familiarity with your programming language of choice. Let's create a simple workflow that runs whenever code is pushed to your repository:
- Create a .github directory in your repository if it doesn't exist.
- Add a new file called hello-world.yml with the following content:
1name: Hello World
2on:
3 push:
4 branches: [ main ]
5
6jobs:
7 hello:
8 runs-on: ubuntu-latest
9 steps:
10 - name: Say Hello
11 run: echo 'Hello, Github Actions!'
12
13 - name: Show Date
14 run: date
Breaking Down the Workflow:
Trigger:on: push: branches: [ main ] - The workflow runs automatically whenever code is pushed to the main branch of your repository.
Jobs: hello: - Defines a single job named "hello" that will execute the steps. runs-on: ubuntu-latest - This job runs on the latest version of Ubuntu provided by GitHub Actions.
Steps: Step 1 (Say Hello) : Outputs the text "Hello, Github Actions!" to the console log using the echo command.
Step 2 (Show Date): Runs the date command to display the current date and time on the runner.
In summary, when you push code to the main branch, GitHub Actions automatically spins up an Ubuntu virtual machine that executes your workflow. The system prints "Hello, Github Actions!" and displays the current date and time. You can see logs of each run including all command outputs by visiting the Actions tab in your GitHub repository.
Viewing Workflow Results
After pushing this file to your repository:
- Go to your repository on GitHub
- Click on the "Actions" tab
- You should see your "Hello World" workflow running or completed
- Click on the workflow run to see details about each step

GitHub Actions workflow showing successful execution of a simple 'Hello World' job with timestamp output.
Understanding YAML Syntax
YAML Basics for GitHub Actions
YAML (YAML Ain't Markup Language) is the language used to define GitHub Actions workflows. Here are some key aspects:
- Indentation matters (use spaces, not tabs)
- Key-value pairs are defined with a colon (
key: value
) - Lists are defined with hyphens (
- item
) - Comments start with
#
Common YAML Structures in GitHub Actions
1# String
2name: My Workflow
3
4# Boolean
5continue-on-error: true
6
7# Number
8timeout-minutes: 10
9
10# List/Array
11branches:
12- main
13- develop
14
15# Dictionary/Map
16env:
17NODE_VERSION: '16'
18DEBUG: 'true'
19
20# Multi-line string
21run: |
22echo "Line 1"
23echo "Line 2"
YAML Gotchas
- Strings that look like numbers or booleans should be quoted:
version: '12'
- Be careful with special characters:
password: 'p@$$w0rd!'
- Maintain consistent indentation throughout the file
Workflow Triggers
Event Types
GitHub Actions workflows are triggered by events that occur in your repository:
Repository Events
- push: When code is pushed to the repository
- pull_request: When a pull request is opened, synchronized, or closed
- create: When a branch or tag is created
- delete: When a branch or tag is deleted
- fork: When the repository is forked
- issues: When an issue is opened, edited, closed, etc.
- issue_comment`: When a comment is added to an issue or pull request
- watch: When someone stars the repository
- release: When a release is created, edited, or published
Example: Trigger on Push and Pull Request
1on:
2push:
3 branches: [ main, develop ]
4pull_request:
5 branches: [ main ]
Schedule-Based Triggers
You can also schedule workflows using cron syntax:
1on:
2schedule:
3 # Run at 00:00 every day
4 - cron: '0 0 * * *'
Manual Triggers
The workflow_dispatch event allows manual triggering:
1on:
2workflow_dispatch:
3 inputs:
4 environment:
5 description: 'Environment to deploy to'
6 required: true
7 default: 'staging'
8 type: choice
9 options:
10 - staging
11 - production
Filtering Events
You can filter events based on specific conditions:
1on:
2push:
3 branches: # Filter by branch name
4 - main
5 - 'releases/**' # Pattern matching
6 tags: # Filter by tag name
7 - 'v*' # All version tags
8 paths: # Filter by modified file paths
9 - 'src/**' # Only trigger on src directory changes
10 - '!docs/**' # Ignore changes to docs directory
Using Activity Types
Some events have subtypes called "activity types":
1on:
2issues:
3 types: [opened, labeled, closed]
4pull_request:
5 types: [opened, synchronize, reopened]
Jobs and Steps
Jobs
Jobs are collections of steps that run on the same runner. By default, jobs run in parallel, but they can be configured to run sequentially.
1jobs:
2build:
3 runs-on: ubuntu-latest
4 steps:
5 # Steps go here
6
7test:
8 needs: build # This job will run after 'build' completes
9 runs-on: ubuntu-latest
10 steps:
11 # Steps go here
Job Properties
- runs-on: Specifies the runner environment
- needs: Defines job dependencies
- if: Conditional execution
- timeout-minutes: Maximum duration
- strategy: Defines matrix builds
- env: Job-level environment variables
- outputs: Defines job outputs
Steps
Steps are individual tasks within a job that execute commands or actions.
1steps:
2- name: Check out code
3 uses: actions/checkout@v3
4
5- name: Install dependencies
6 run: npm install
7
8- name: Run tests
9 run: npm test
Step Properties
- name: A descriptive name for the step
- uses: References an action to run
- run: Executes a command
- with: Provides inputs to an action
- env: Step-level environment variables
- if: Conditional execution
- continue-on-error: Whether to continue on failure
Controlling Job Flow
You can create dependencies between jobs using the needs property:
1jobs:
2setup:
3 runs-on: ubuntu-latest
4 steps:
5 # Setup steps here
6
7build:
8 needs: setup
9 runs-on: ubuntu-latest
10 steps:
11 # Build steps here
12
13test:
14 needs: build
15 runs-on: ubuntu-latest
16 steps:
17 # Test steps here
18
19deploy:
20 needs: [build, test] # Multiple dependencies
21 if: github.ref == 'refs/heads/main' # Conditional execution
22 runs-on: ubuntu-latest
23 steps:
24 # Deploy steps here
Conditionals in Jobs and Steps
Use conditionals to control when jobs and steps execute:
1jobs:
2deploy:
3 if: github.event_name == 'push' && github.ref == 'refs/heads/main'
4 runs-on: ubuntu-latest
5 steps:
6 - name: Production deploy
7 if: github.repository == 'owner/repo'
8 run: ./deploy.sh production
9
10 - name: Staging deploy
11 if: github.repository != 'owner/repo'
12 run: ./deploy.sh staging
Using Actions
What Are Actions?
Actions are reusable units of code that perform a specific task. They're the building blocks of GitHub Actions workflows.
Types of Actions
- 1. JavaScript actions: Built with JavaScript/TypeScript
- 2. Docker container actions: Run in a Docker environment
- 3. Composite actions: Combine multiple steps in one action
Using Community Actions
The GitHub Marketplace has thousands of pre-built actions:
1steps:
2# Check out the repository
3- uses: actions/checkout@v3
4
5# Set up Node.js
6- uses: actions/setup-node@v3
7 with:
8 node-version: '16'
9
10# Cache dependencies
11- uses: actions/cache@v3
12 with:
13 path: ~/.npm
14 key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
Action Versioning
Always specify a version when using actions to ensure stability:
- uses: actions/checkout@v3: Use major version 3
- uses: actions/checkout@v3.1.0: Use specific version 3.1.0
- uses: actions/checkout@main: Use latest (risky for production)
Popular GitHub Actions
- actions/checkout: Checks out your repository
- actions/setup-node: Sets up Node.js
- actions/setup-python: Sets up Python
- actions/setup-java: Sets up Java
- actions/cache: Caches dependencies
- actions/upload-artifact: Uploads build artifacts
- actions/download-artifact: Downloads build artifacts
Example: Setting Up a Node.js Environment
1name: Node.js CI
2
3on: [push, pull_request]
4
5jobs:
6build:
7 runs-on: ubuntu-latest
8 steps:
9 - uses: actions/checkout@v3
10
11 - name: Use Node.js
12 uses: actions/setup-node@v3
13 with:
14 node-version: '16'
15 cache: 'npm'
16
17 - name: Install dependencies
18 run: npm ci
19
20 - name: Run tests
21 run: npm test
Conclusion
Congratulations! You've completed Part 1 of our GitHub Actions series and are now equipped with the fundamental knowledge to start automating your development workflows. You've learned how to create workflow files, understand YAML syntax, configure various triggers, organize jobs and steps, and leverage community actions to accelerate your productivity. These building blocks will serve as the foundation for more advanced automation techniques we'll explore in upcoming tutorials.
By implementing what you've learned today, you're already positioned to significantly improve your development process. Simple automations like running tests on every pull request or deploying your application when changes are pushed to the main branch can save countless hours and reduce human error. Remember that effective CI/CD isn't just about technical implementation—it's about creating a smoother, more reliable development experience for your entire team.
In Part 2, we'll dive deeper into advanced GitHub Actions features including environment secrets, artifact management, matrix builds, and custom action development. Until then, try creating a few workflows in your own repositories to reinforce these concepts and discover the immediate benefits of automated workflows. Happy coding!