Setting Up a CI/CD Pipeline with GitHub Actions for Laravel
February 5, 2026 · 9 min read
Introduction
Continuous Integration and Continuous Deployment (CI/CD) is an essential practice for modern software teams. For Laravel projects, a well-configured CI/CD pipeline automates testing, code quality checks, and deployment — reducing human error and speeding up release cycles. GitHub Actions provides a powerful, integrated CI/CD platform directly in your repository. This guide walks you through setting up a complete pipeline for a Laravel application.
What is CI/CD and Why It Matters for Laravel
CI/CD automates the steps between writing code and deploying it to production. For Laravel projects, this means running PHPUnit tests on every pull request, checking code style with Laravel Pint, and deploying to production with zero downtime. A good pipeline catches bugs early, enforces code standards, and makes deployments predictable and reversible.
GitHub Actions Basics
GitHub Actions workflows are defined as YAML files in the .github/workflows/ directory. Each workflow consists of one or more jobs that run on specified events (push, pull_request, release). Jobs run on GitHub-hosted runners or self-hosted runners. The key concepts are: events (triggers), jobs (units of work), steps (individual commands), and actions (reusable units).
Testing Workflow: PHPUnit, Dusk, and Pint
Create .github/workflows/tests.yml to run on every push and pull request:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
ports: [3306/tcp]
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with: { php-version: '8.2' }
- run: composer install --no-progress
- run: cp .env.example .env
- run: php artisan key:generate
- run: php artisan migrate --env=testing
- run: ./vendor/bin/phpunit
- run: ./vendor/bin/pint --test
For Laravel Dusk (browser tests), you'll need to install Chrome and run the Dusk-specific commands in a separate job or step.
Deployment Workflow: Deployer and SSH
Deployer is a PHP-based deployment tool that integrates perfectly with Laravel. Install it with composer require --dev deployer/deployer. Create a deploy.php recipe defining your servers, repository, and deploy path. Then create a GitHub Actions workflow that runs only on pushes to the main branch:
name: Deploy
on:
push: { branches: [main] }
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with: { php-version: '8.2' }
- run: composer install --no-dev --optimize-autoloader
- run: npm ci && npm run build
- name: Deploy with Deployer
uses: deployphp/action@v1
with:
dep: deploy
private-key: ${{ secrets.DEPLOY_KEY }}
Environment Management
Never commit .env files. Store production secrets as GitHub Actions Secrets (Settings → Secrets and variables → Actions). Use GitHub Environments to create separate variable sets for staging and production with required reviewers for production deployments. In your Deployer recipe, reference $secret('APP_KEY') for sensitive values.
Database Migration Strategy
Deployer automatically runs php artisan migrate during deployment. For zero-downtime, structure migrations to be backward-compatible: add columns with nullable() first, deploy, backfill data, then add the NOT NULL constraint in a second deployment. For large tables, use ALGORITHM=INPLACE, LOCK=NONE in migration statements.
Notifications: Slack and Email
GitHub Actions supports built-in notification actions. Add Slack notifications on failure using the slackapi/slack-github-action action. For email notifications, use dawidd6/action-send-mail. Integrate these as the final step in your workflow, conditional on failure:
- if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: '{"text":"Deploy failed!"}'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Zero-Downtime Deployment with Laravel Horizon
Laravel Horizon manages Redis queues with a beautiful dashboard. During deployment, gracefully terminate Horizon workers before deploying, then restart them after. Deployer's php artisan horizon:terminate and php artisan horizon:pause/horizon:continue commands handle this. For the web server, use a process manager like Supervisor and reload workers with supervisorctl reload.
Conclusion
A solid CI/CD pipeline transforms your development workflow. Testing becomes automatic, deployments become boring (in a good way), and you ship features faster with more confidence. Start with a simple test workflow, add deployment gradually, and iterate based on your team's needs. The investment in CI/CD setup pays for itself in the first deployment emergency it prevents.
Need help setting up CI/CD for your Laravel project? We provide DevOps consulting, pipeline setup, and deployment automation for teams of all sizes.
Hire Us