Deploy Laravel Project with GitHub Actions CI/CD Workflow


Introduction
In this guide, you’ll learn how to set up a deploy script for your Laravel project and integrate it seamlessly with a GitHub Actions workflow. We’ll walk through crafting a deployment script for your production server and explain each step of a GitHub Actions pipeline that tests and deploys your application whenever changes are pushed to the main
branch. By the end, you’ll have a reliable and repeatable process to keep your Laravel application up to date with minimal manual effort.
Laravel Deploy Script
First we need to write a Laravel deploy script that will be triggered from our GitHub Actions workflow. Make sure to store this file in your production server. Nothing fancy here, those are all commands that we use while developing. Have a look:
# Change your Laravel project directorycd ~/mywebsite # Turn on maintenance modephp artisan down || true # Pull the latest changes from the git repositorygit pull origin main # Install composer dependeciescomposer install --no-interaction --no-dev # Optimize filament components and blade iconsphp artisan filament:optimize-clearphp artisan filament:optimize # Optimize view, routes, events, configsphp artisan optimize:clearphp artisan optimize # Clear cachesphp artisan cache:clear # Clear expired password reset tokensphp artisan auth:clear-resets # Run database migrationsphp artisan migrate --force # Turn off maintenance modephp artisan up exit 0
GitHub Actions Workflow to Test & Deploy Laravel
Next, we will write our GitHub Actions workflow that does two things in particular; Runs tests, and deploys to server. In the root directory of your Laravel project, create .github
folder and inside .github
, create workflows
folder. You will end up with a .github/workflows
structure. Create a YAML file e.g. tests.yml
and save it in the workflows folder.
This workflow will be triggered when changes are pushed to the main
branch. Let's see the workflow:
name: mywebsite.com on: push: branches: ["main"] jobs: test-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e with: php-version: "8.2" - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "22.x" cache: "npm" - name: Copy .env run: php -r "file_exists('.env') || copy('.env.example', '.env');" - name: Install PHP Dependencies run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: Generate key run: php artisan key:generate - name: Directory Permissions run: chmod -R 777 storage bootstrap/cache - name: Install and Build Frontend Dependencies run: | npm install npm run build --if-present - name: Execute tests run: composer test:ci - name: Deploy to Server with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: cd scripts && sh deploy_script.sh
We will go through each step and understand what each step of the workflow does. Let's go.
e.g. mywebsite.com
Workflow Name: The workflow is triggered on any push
to the main
branch. The workflow performs testing and deployment for a Laravel application (it could be your website or an API server or anything else).
Trigger Event
-
on: push
:- Runs this workflow whenever changes are pushed to the
main
branch.
- Runs this workflow whenever changes are pushed to the
e.g. test-and-deploy
Job: This job is executed on an Ubuntu environment (ubuntu-latest
) and consists of multiple steps.
- Checkout Code
- name: Checkout code uses: actions/checkout@v3
- Action: Downloads the repository code to the runner.
- Purpose: Ensures the workflow has access to the latest application files.
- Setup PHP
- name: Setup PHP uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e with: php-version: "8.2"
- Action: Sets up PHP version 8.2 on the runner (i.e. Ubuntu).
- Purpose: Prepares the environment to execute PHP-based tasks such as running Laravel commands or installing dependencies.
- Set up Node.js
- name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "22.x" cache: "npm"
-
Action: Installs Node.js version 22.x and enables caching for
npm
. - Purpose: Provides the required Node.js environment to build and manage frontend assets.
-
Copy
.env
File
- name: Copy .env run: php -r "file_exists('.env') || copy('.env.example', '.env');"
-
Action: Checks if a
.env
file exists; if not, it creates one by copying from.env.example
. - Purpose: Ensures that the application has the necessary environment configuration file.
- Install PHP Dependencies
- name: Install PHP Dependencies run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- Action: Installs Laravel's PHP dependencies using Composer with optimized settings.
- Purpose: Prepares backend dependencies for the Laravel application.
- Generate Application Key
- name: Generate key run: php artisan key:generate
-
Action: Runs the
key:generate
Artisan command to create an encryption key. - Purpose: Ensures the Laravel application has a valid encryption key.
- Set Directory Permissions
- name: Directory Permissions run: chmod -R 777 storage bootstrap/cache
-
Action: Sets writable permissions for
storage
andbootstrap/cache
directories. - Purpose: Ensures these directories are writable for Laravel to store cached files and logs.
- Install and Build Frontend Dependencies
- name: Install and Build Frontend Dependencies run: | npm install npm run build --if-present
-
Action:
- Installs frontend dependencies using
npm install
. - Builds the frontend assets using
npm run build
if a build script is defined.
- Installs frontend dependencies using
- Purpose: Prepares and compiles the frontend assets.
- Execute Tests
- name: Execute tests run: composer test
- Action: Runs the PHP tests or any configured tests using a Composer command.
- Purpose: Validates the application's functionality by executing automated tests.
- Deploy to Server
- name: Deploy to Server with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: cd scripts && sh deploy_script.sh
-
Action:
- Connects to the deployment server via SSH using credentials stored as GitHub Secrets.
- Executes the deployment script (
deploy_script.sh
) located in thescripts
directory.
- Purpose: Automates deployment to the production server.
Conclusion
With the deploy script and GitHub Actions workflow in place, managing your Laravel application's deployment becomes significantly more efficient and less error-prone. You’ve set up an automated process that handles everything from testing your code to deploying it to the production server with just a push to the main
branch. This approach not only saves time but also ensures consistent deployments, allowing you to focus on building features rather than worrying about manual setups. Whether you’re maintaining a website or an API server, this streamlined workflow is a game-changer for Laravel developers.
Stay Updated.
I'll you email you as soon as new, fresh content is published.