{"id":441,"date":"2025-08-27T22:01:40","date_gmt":"2025-08-27T22:01:40","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=441"},"modified":"2025-08-27T22:21:11","modified_gmt":"2025-08-27T22:21:11","slug":"step-by-step-ci-cd-pipeline-setup-for-laravel-12-on-github-actions","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/step-by-step-ci-cd-pipeline-setup-for-laravel-12-on-github-actions\/","title":{"rendered":"Step-by-Step CI\/CD Pipeline Setup for Laravel 12 on GitHub Actions"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>Step-by-Step CI\/CD Pipeline Setup for Laravel 12 on GitHub Actions<\/strong><\/h2>\n\n\n\n<p>Continuous Integration and Continuous Deployment (CI\/CD) ensures your Laravel 12 projects are always tested, built, and deployed automatically. With <strong>GitHub Actions<\/strong>, you can build pipelines that handle testing, asset compilation, and server deployment whenever you push to your main branch. In this tutorial, we\u2019ll build a full CI\/CD pipeline step by step, integrating with services like DigitalOcean, AWS, and even Docker-based flows.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>1 \u2014 Why Use CI\/CD with Laravel?<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Consistency:<\/strong> Every push runs tests in the same environment (Docker\/Ubuntu runners).<\/li>\n\n\n\n<li><strong>Speed:<\/strong> No more manual deployments\u2014production updates are automated.<\/li>\n\n\n\n<li><strong>Quality:<\/strong> Run PHPUnit, PHPStan, and Laravel Dusk before deploys.<\/li>\n\n\n\n<li><strong>Scalability:<\/strong> Works equally well with EC2, DigitalOcean, or any cloud provider.<\/li>\n<\/ul>\n\n\n\n<p>If you\u2019ve already set up <a href=\"\/blog\/how-to-deploy-a-laravel-12-app-on-digitalocean\">DigitalOcean Deployments<\/a>  or <a href=\"\/blog\/deploying-laravel-on-aws-complete-guide-2025\">AWS Deployments<\/a>, CI\/CD ensures those environments are updated safely and automatically.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2 \u2014 Basic GitHub Actions Workflow<\/strong><\/h2>\n\n\n\n<p>Create a workflow file in your Laravel repo at <code>.github\/workflows\/ci.yml<\/code>. This runs tests and builds assets on every push to main.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-comment\"># .github\/workflows\/ci.yml<\/span>\n<span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">CI<\/span>\n\n<span class=\"hljs-attr\">on:<\/span>\n  <span class=\"hljs-attr\">push:<\/span>\n    <span class=\"hljs-attr\">branches:<\/span> <span class=\"hljs-string\">&#91;<\/span> <span class=\"hljs-string\">\"main\"<\/span> <span class=\"hljs-string\">]<\/span>\n  <span class=\"hljs-attr\">pull_request:<\/span>\n\n<span class=\"hljs-attr\">jobs:<\/span>\n  <span class=\"hljs-attr\">build-test:<\/span>\n    <span class=\"hljs-attr\">runs-on:<\/span> <span class=\"hljs-string\">ubuntu-latest<\/span>\n    <span class=\"hljs-attr\">steps:<\/span>\n      <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">actions\/checkout@v4<\/span>\n\n      <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Set<\/span> <span class=\"hljs-string\">up<\/span> <span class=\"hljs-string\">PHP<\/span>\n        <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">shivammathur\/setup-php@v2<\/span>\n        <span class=\"hljs-attr\">with:<\/span>\n          <span class=\"hljs-attr\">php-version:<\/span> <span class=\"hljs-string\">'8.3'<\/span>\n          <span class=\"hljs-attr\">extensions:<\/span> <span class=\"hljs-string\">mbstring,<\/span> <span class=\"hljs-string\">bcmath,<\/span> <span class=\"hljs-string\">pdo_mysql<\/span>\n\n      <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Install<\/span> <span class=\"hljs-string\">Composer<\/span> <span class=\"hljs-string\">dependencies<\/span>\n        <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">composer<\/span> <span class=\"hljs-string\">install<\/span> <span class=\"hljs-string\">--no-interaction<\/span> <span class=\"hljs-string\">--no-progress<\/span> <span class=\"hljs-string\">--prefer-dist<\/span>\n\n      <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Run<\/span> <span class=\"hljs-string\">tests<\/span>\n        <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">php<\/span> <span class=\"hljs-string\">artisan<\/span> <span class=\"hljs-string\">test<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This workflow installs PHP 8.3 with required extensions, pulls dependencies, and runs Laravel\u2019s test suite. It ensures every commit is validated before deploying.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3 \u2014 Building Frontend Assets<\/strong><\/h2>\n\n\n\n<p>If your app uses Vite for assets, add Node to the pipeline and build before deployment.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Set<\/span> <span class=\"hljs-string\">up<\/span> <span class=\"hljs-string\">Node.js<\/span>\n  <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">actions\/setup-node@v4<\/span>\n  <span class=\"hljs-attr\">with:<\/span>\n    <span class=\"hljs-attr\">node-version:<\/span> <span class=\"hljs-number\">20<\/span>\n\n<span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Install<\/span> <span class=\"hljs-string\">NPM<\/span> <span class=\"hljs-string\">packages<\/span>\n  <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">npm<\/span> <span class=\"hljs-string\">ci<\/span>\n\n<span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Build<\/span> <span class=\"hljs-string\">assets<\/span>\n  <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">npm<\/span> <span class=\"hljs-string\">run<\/span> <span class=\"hljs-string\">build<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This step ensures your CSS and JS are compiled, ready for production. Combined with <code>php artisan config:cache<\/code> and <code>route:cache<\/code>, it results in fast deployments (see <a href=\"\/blog\/10-proven-ways-to-optimize-laravel-for-high-traffic\">High Traffic Optimization<\/a>).<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>4 \u2014 Deployment to DigitalOcean (via SSH)<\/strong><\/h2>\n\n\n\n<p>One simple approach is deploying with SSH and Rsync. Store your server\u2019s SSH key in GitHub Secrets.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Deploy<\/span> <span class=\"hljs-string\">to<\/span> <span class=\"hljs-string\">DigitalOcean<\/span>\n  <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">appleboy\/ssh-action@v1.2.0<\/span>\n  <span class=\"hljs-attr\">with:<\/span>\n    <span class=\"hljs-attr\">host:<\/span> <span class=\"hljs-string\">${{<\/span> <span class=\"hljs-string\">secrets.DO_HOST<\/span> <span class=\"hljs-string\">}}<\/span>\n    <span class=\"hljs-attr\">username:<\/span> <span class=\"hljs-string\">${{<\/span> <span class=\"hljs-string\">secrets.DO_USER<\/span> <span class=\"hljs-string\">}}<\/span>\n    <span class=\"hljs-attr\">key:<\/span> <span class=\"hljs-string\">${{<\/span> <span class=\"hljs-string\">secrets.DO_SSH_KEY<\/span> <span class=\"hljs-string\">}}<\/span>\n    <span class=\"hljs-attr\">script:<\/span> <span class=\"hljs-string\">|\n      cd \/var\/www\n      .\/deploy.sh<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This uses the <code>ssh-action<\/code> to connect and run your <code>deploy.sh<\/code> (see #51 for a full zero-downtime script). It\u2019s straightforward and great for single-server setups.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>5 \u2014 Deployment to AWS (CodeDeploy)<\/strong><\/h2>\n\n\n\n<p>For AWS, we recommend using CodeDeploy. Combine this with OIDC for GitHub Actions so no static IAM keys are needed.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Configure<\/span> <span class=\"hljs-string\">AWS<\/span> <span class=\"hljs-string\">creds<\/span>\n  <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">aws-actions\/configure-aws-credentials@v4<\/span>\n  <span class=\"hljs-attr\">with:<\/span>\n    <span class=\"hljs-attr\">role-to-assume:<\/span> <span class=\"hljs-string\">arn:aws:iam::123456789012:role\/GitHubDeployRole<\/span>\n    <span class=\"hljs-attr\">aws-region:<\/span> <span class=\"hljs-string\">us-east-1<\/span>\n\n<span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Upload<\/span> <span class=\"hljs-string\">to<\/span> <span class=\"hljs-string\">S3<\/span>\n  <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">aws<\/span> <span class=\"hljs-string\">s3<\/span> <span class=\"hljs-string\">cp<\/span> <span class=\"hljs-string\">deploy.zip<\/span> <span class=\"hljs-string\">s3:\/\/your-bucket\/deploy.zip<\/span>\n\n<span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Trigger<\/span> <span class=\"hljs-string\">CodeDeploy<\/span>\n  <span class=\"hljs-attr\">run:<\/span> <span class=\"hljs-string\">|\n    aws deploy create-deployment \\\n      --application-name laravel-app \\\n      --deployment-group-name laravel-asg \\\n      --s3-location bucket=your-bucket,key=deploy.zip,bundleType=zip<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This triggers a rolling deploy across your Auto Scaling Group without downtime. For the full AWS walkthrough, see <a href=\"\/blog\/deploying-laravel-on-aws-complete-guide-2025\">AWS Guide<\/a>.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>6 \u2014 Caching for Faster Pipelines<\/strong><\/h2>\n\n\n\n<p>Caching Composer and NPM dependencies drastically speeds up builds. Use GitHub\u2019s cache action.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Cache<\/span> <span class=\"hljs-string\">Composer<\/span>\n  <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">actions\/cache@v4<\/span>\n  <span class=\"hljs-attr\">with:<\/span>\n    <span class=\"hljs-attr\">path:<\/span> <span class=\"hljs-string\">vendor<\/span>\n    <span class=\"hljs-attr\">key:<\/span> <span class=\"hljs-string\">${{<\/span> <span class=\"hljs-string\">runner.os<\/span> <span class=\"hljs-string\">}}-composer-${{<\/span> <span class=\"hljs-string\">hashFiles('**\/composer.lock')<\/span> <span class=\"hljs-string\">}}<\/span>\n\n<span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-attr\">name:<\/span> <span class=\"hljs-string\">Cache<\/span> <span class=\"hljs-string\">NPM<\/span>\n  <span class=\"hljs-attr\">uses:<\/span> <span class=\"hljs-string\">actions\/cache@v4<\/span>\n  <span class=\"hljs-attr\">with:<\/span>\n    <span class=\"hljs-attr\">path:<\/span> <span class=\"hljs-string\">~\/.npm<\/span>\n    <span class=\"hljs-attr\">key:<\/span> <span class=\"hljs-string\">${{<\/span> <span class=\"hljs-string\">runner.os<\/span> <span class=\"hljs-string\">}}-npm-${{<\/span> <span class=\"hljs-string\">hashFiles('**\/package-lock.json')<\/span> <span class=\"hljs-string\">}}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Each run reuses cached dependencies unless <code>composer.lock<\/code> or <code>package-lock.json<\/code> changes, saving minutes. This is part of larger optimization strategies\u2014see <a href=\"\/blog\/10-proven-ways-to-optimize-laravel-for-high-traffic\">10 Proven Ways to Optimize Laravel for High Traffic<\/a>.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>7 \u2014 Deployment Status UI (Optional)<\/strong><\/h2>\n\n\n\n<p>You can add a simple admin-only UI in Laravel to display the last GitHub Actions deployment status by consuming the GitHub API.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ routes\/web.php<\/span>\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Support<\/span>\\<span class=\"hljs-title\">Facades<\/span>\\<span class=\"hljs-title\">Http<\/span>;\n\nRoute::middleware(&#91;<span class=\"hljs-string\">'auth'<\/span>, <span class=\"hljs-string\">'can:viewAdmin'<\/span>])-&gt;get(<span class=\"hljs-string\">'\/deploy-status'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">()<\/span> <\/span>{\n    $response = Http::withToken(config(<span class=\"hljs-string\">'services.github.token'<\/span>))\n        -&gt;get(<span class=\"hljs-string\">'https:\/\/api.github.com\/repos\/your-org\/your-repo\/actions\/runs?per_page=1'<\/span>);\n    $run = $response-&gt;json(<span class=\"hljs-string\">'workflow_runs.0'<\/span>);\n    <span class=\"hljs-keyword\">return<\/span> view(<span class=\"hljs-string\">'admin.deploy'<\/span>, &#91;<span class=\"hljs-string\">'run'<\/span> =&gt; $run]);\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This route calls the GitHub Actions API for the latest workflow run and passes it to a Blade view. Store a GitHub PAT in <code>config\/services.php<\/code> for authentication.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-comment\">&lt;!-- resources\/views\/admin\/deploy.blade.php --&gt;<\/span>\n@extends('layouts.app')\n@section('content')\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"mb-4\"<\/span>&gt;<\/span>Latest Deployment<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong<\/span>&gt;<\/span>Workflow:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">strong<\/span>&gt;<\/span> {{ $run&#91;'name'] }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong<\/span>&gt;<\/span>Status:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">strong<\/span>&gt;<\/span> {{ $run&#91;'status'] }} \/ {{ $run&#91;'conclusion'] ?? 'in-progress' }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong<\/span>&gt;<\/span>Commit:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">strong<\/span>&gt;<\/span> {{ $run&#91;'head_commit']&#91;'message'] }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"{{ $run&#91;'html_url'] }}\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"btn btn-theme\"<\/span> <span class=\"hljs-attr\">target<\/span>=<span class=\"hljs-string\">\"_blank\"<\/span>&gt;<\/span>View in GitHub<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n@endsection<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With this UI, your team can see at a glance if the last deployment succeeded\u2014without leaving your app. For debugging failed jobs, you can also integrate with <a href=\"\/blog\/using-laravel-telescope-to-debug-performance-issues\">Using Laravel Telescope to Debug Performance Issues<\/a>.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>A well-structured GitHub Actions pipeline makes your Laravel 12 workflow smooth: test every commit, build assets, cache dependencies, and deploy automatically to DigitalOcean or AWS. This not only saves time but also ensures reliability and confidence with every release.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s Next<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/how-to-deploy-a-laravel-12-app-on-digitalocean\">How to Deploy a Laravel 12 App on DigitalOcean<\/a> \u2014 pair CI\/CD with DO Droplet deployments.<\/li>\n\n\n\n<li><a href=\"\/blog\/deploying-laravel-on-aws-complete-guide-2025\">Deploying Laravel on AWS: Complete Guide (2025)<\/a>  \u2014 full AWS production pipelines.<\/li>\n\n\n\n<li><a href=\"\/blog\/laravel-deployment-checklist-for-2025\">Laravel Deployment Checklist for 2025<\/a>  \u2014 run this before every release.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Step-by-Step CI\/CD Pipeline Setup for Laravel 12 on GitHub Actions Continuous Integration and Continuous Deployment (CI\/CD) ensures your Laravel 12 projects are always tested, built, and deployed automatically. With GitHub Actions, you can build pipelines that handle testing, asset compilation, and server deployment whenever you push to your main branch. In this tutorial, we\u2019ll build [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":445,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[80,71,78,79],"class_list":["post-441","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-ci-cd","tag-devops","tag-eployment","tag-github-actions"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/441","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=441"}],"version-history":[{"count":2,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/441\/revisions"}],"predecessor-version":[{"id":462,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/441\/revisions\/462"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/445"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}