Automate Your Deployments: A Step-by-Step Guide to Using GitHub Actions for Seamless Continuous Deployment
Let’s be honest: manually deploying code is a chore. It’s error-prone, time-consuming, and the exact opposite of what we should be doing as developers. If you’re still pushing to production by hand, you’re wasting time you could spend building features, fixing bugs, or even just going home on time.
GitHub Actions gives you a powerful, free way to automate deployments right from your repo. No extra CI/CD tools, no complex setup—just YAML and a few clicks. In this guide, I’ll walk you through setting up a real-world continuous deployment pipeline using GitHub Actions.
1. Understand the Flow: What Are We Automating?
Before we write any code, let’s define what we want:
- On every push to the
mainbranch:- Run tests
- Build the app
- Deploy to a server or platform (we’ll use a VPS via SSH as an example)
This is continuous deployment: merge code → tests run → if they pass, it ships.
2. Set Up Your Project Structure
Assume you have a simple Node.js app (but this applies to any language). Your repo looks like:
my-app/
├── package.json
├── server.js
├── .github/workflows/deploy.yml # ← This is where the magic happens
The key is the .github/workflows/deploy.yml file. That’s where GitHub Actions lives.
3. Create the GitHub Actions Workflow
Start by creating .github/workflows/deploy.yml. Here’s a minimal, working example:
name: Deploy to Production
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Build app
run: npm run build
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.2
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: 22
script: |
cd /var/www/my-app
git pull origin main
npm install
npm run build
pm2 restart my-app
Let’s break this down:
-
on.push.branches: Trigger on every push tomain. -
actions/checkout: Pulls your code onto the runner. -
setup-node: Installs Node.js 18. - Then we run the usual: install, test, build.
- Finally, we use
appleboy/ssh-actionto SSH into our server and run deployment commands.
4. Store Secrets in GitHub
You never hardcode credentials. Instead, go to:
Repo Settings → Secrets and variables → Actions → New repository secret
Add these:
| Name | Value |
|---|---|
SSH_HOST |
Your server IP or domain |
SSH_USER |
Your server username (e.g., ubuntu) |
SSH_KEY |
Your private SSH key (use -----BEGIN OPENSSH PRIVATE KEY----- format) |
Pro tip: Generate a deploy key with limited access. Don’t use your personal SSH key.
5. Handle Failures Gracefully
Your pipeline should fail fast and notify you.
Add a notification step (optional but useful):
- name: Notify on failure
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Deployment failed for ${{ github.ref }}',
body: 'Check the workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
})
This creates a GitHub issue if the deploy fails. Simple, effective.
6. Optimize for Real-World Use
Skip deployments on docs-only changes
You don’t need to deploy just because someone updated a README.
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
Or, better: use paths to only trigger when code changes:
paths:
- 'src/**'
- 'package.json'
- 'package-lock.json'
Cache dependencies
Speed up runs by caching node_modules:
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
7. Deploy to Other Platforms?
This SSH example works for VPS setups (like DigitalOcean, Linode, etc.). But if you’re using platforms like:
- Vercel / Netlify: They have their own GitHub integrations. Still, you can trigger deploys via API.
- Render / Railway: Use their CLI or API in the workflow.
☕ Playful tone: "Fuel my coding adventures with a virtual coffee (or a real one, if you're feeling generous)! Your support on Ko-fi helps me keep creating free tools and articles: https://ko-fi.com/orbitwebsites"
Top comments (0)