How to Create Your First GitHub Actions Workflow: A Beginner's Guide
When I first tried automating my repository tasks, I kept doing everything manually - running tests, labeling issues, deploying changes. Then I discovered GitHub Actions, and I realized I could automate all of this with a single YAML file.
I struggled at first with YAML syntax errors and permission issues. After several failed attempts, I finally understood the structure. Here’s what I learned about creating your first GitHub Actions workflow.
Understanding the Workflow Structure
GitHub Actions workflows use YAML syntax with three main sections:
- name: A descriptive title for your workflow
- on: Triggers that start the workflow
- jobs: The actual work to perform
GitHub provides hosted runners (Ubuntu, Windows, macOS) at no cost for public repositories. You don’t need to set up any servers.
The uses keyword pulls prebuilt actions from GitHub Marketplace, while run executes shell commands directly. GitHub also automatically creates a GITHUB_TOKEN for authentication in your workflows.
Creating Your First Workflow
Step 1: Create the Workflow Directory
In your repository, create the .github/workflows/ directory. This exact path is required - placing files anywhere else won’t work.
Step 2: Choose a Descriptive Filename
Use clear, purpose-driven names like build-and-test.yml or label-new-issue.yml. Avoid generic names like workflow.yml or ci.yml.
Step 3: Define Your Workflow
Here’s a complete example that automatically labels new issues:
name: Label New Issues
on: issues: types: [opened]
jobs: label-issues: runs-on: ubuntu-latest permissions: issues: write contents: read steps: - name: Checkout repository uses: actions/checkout@v6 - name: Add triage label env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} LABEL: "triage" run: gh issue edit "$ISSUE_NUMBER" --add-label "$LABEL"Let me break down each part:
name: Label New IssuesThis appears in the Actions tab of your repository, making it easy to identify.
on: issues: types: [opened]The on section defines when this workflow runs. Here, it triggers when a new issue is opened.
jobs: label-issues: runs-on: ubuntu-latestEach job needs a runner. ubuntu-latest is the most common choice and works for most workflows.
permissions: issues: write contents: readPermissions control what your workflow can access. Without issues: write, the workflow would fail when trying to add labels.
steps: - name: Checkout repository uses: actions/checkout@v6The uses keyword references an action from GitHub Marketplace. The checkout action is essential - it clones your repository so subsequent steps can access your code.
- name: Add triage label env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} LABEL: "triage" run: gh issue edit "$ISSUE_NUMBER" --add-label "$LABEL"The run keyword executes shell commands. Environment variables are set via env, and GitHub’s context values like github.event.issue.number are accessed with ${{ }} syntax.
Common Trigger Examples
Workflows can trigger on various events:
on: push: branches: [main]on: pull_request: types: [opened, synchronize]on: schedule: - cron: '0 9 * * *'The scheduled trigger uses cron syntax - 0 9 * * * runs daily at 9 AM UTC.
Common Mistakes to Avoid
I made these mistakes when starting out:
Wrong directory location: Placing workflow files directly in .github/ instead of .github/workflows/. The workflow simply won’t be detected.
YAML indentation errors: YAML requires consistent indentation. I once mixed tabs and spaces, causing syntax errors that were hard to debug.
Missing permissions: My workflows failed silently because I forgot to add issues: write for labeling operations. Always check what permissions your workflow needs.
Testing before merging: Workflows only run from the main branch (or default branch) by default. I spent hours debugging a workflow that was never triggered because I hadn’t merged it to main.
Using non-existent labels: When I referenced a label that didn’t exist in my repository, the workflow failed. Make sure labels are created before referencing them.
Testing Your Workflow
After creating your workflow file:
- Commit and push to your repository
- Merge to your main branch (if using a feature branch)
- Trigger the workflow by opening an issue or pushing code (depending on your
onconfiguration) - Navigate to the Actions tab in your repository to view the run
- Click on the workflow run to see detailed logs
Next Steps
Once you’re comfortable with basic workflows, explore:
- Matrix builds: Test across multiple Node.js versions or operating systems
- Secrets management: Store API keys securely in repository settings
- Reusable workflows: Create workflow templates for common patterns
- Environment protection rules: Require approvals before deploying to production
The GitHub Actions Marketplace contains thousands of pre-built actions for common tasks - from deploying to AWS to sending Slack notifications. Before writing custom scripts, check if an action already exists.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 GitHub Actions Documentation
- 👨💻 Workflow Syntax for GitHub Actions
- 👨💻 Events that trigger workflows
- 👨💻 GitHub Actions Marketplace
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments