
September 10, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Build Verification and Quality Gates in CI are the automated checkpoints that decide whether code is safe to merge or deploy. A green local build means little if production still receives broken assets, failing migrations, or unpatched dependencies. On real client projects I maintain with GitLab CI pipelines for Laravel, gates have stopped bad releases more often than manual review ever could. This guide covers gate design, copy-paste pipeline config, and the trade-offs small teams in Nepal and elsewhere actually face.
What are Build Verification and Quality Gates in CI?
Build verification confirms that source code compiles, dependencies resolve, and artefacts build cleanly on a neutral runner. Quality gates add policy on top: tests must pass, coverage must not drop, secrets must not appear in diffs, and known vulnerabilities must stay below a threshold.
Think of the pipeline as a factory line. Build verification is the first inspection station. Quality gates are the inspectors at each later station who reject work that fails spec.
A common mistake is treating CI as a notification system. If a failing test still merges because someone clicks "retry until green," you do not have gates—you have suggestions. Gates only work when the platform enforces them: protected branches, required status checks, and no direct pushes to main.
For background on the wider pipeline picture, see our guide on build pipeline automation best practices and build automation fundamentals.
Build verification vs quality gates
Build verification answers: "Does this code build?" Quality gates answer: "Does this code meet our standards?" The boundary blurs on interpreted stacks like PHP, where "build" often means composer install, asset compilation, and cache warmup rather than compilation.
| Checkpoint type | Typical checks | When it runs | Failure impact |
|---|---|---|---|
| Build verification | Dependency install, Vite/webpack build, Docker image build | Every push and MR | No artefact produced |
| Unit/feature test gate | PHPUnit, Pest, Jest | Every push and MR | Merge blocked |
| Coverage gate | Line/branch threshold vs baseline | MR to main | Merge blocked |
| Security gate | SAST, dependency audit, secret scan | Every push; stricter on main | Merge or deploy blocked |
| Deploy gate | Smoke tests, manual approval, environment promotion | Pre-production and production | Release halted |
How do you set up build verification gates in GitLab CI?
GitLab CI is what I use on most Laravel deployments, including sister legal-tech sites that share a Deployer 7 workflow on Ubuntu servers. The pattern below works on GitLab 17+ with PHP 8.3+ and Laravel 12 or 13.
Official reference: the GitLab CI pipeline efficiency docs cover caching and stage ordering that keep gates fast.
Stage ordering that actually works
Order stages from cheapest to most expensive. Lint and static analysis finish in seconds. Full test suites and security scans take minutes. Put build verification first so downstream jobs skip when dependencies fail.
- validate — syntax, commit message rules, lockfile integrity
- build —
composer install,npm ci, Vite production build - test — unit and feature tests with SQLite or service containers
- quality — coverage diff, PHPStan, SonarQube
- security —
composer audit, secret scanning - deploy — only on protected branches after all prior gates pass
# .gitlab-ci.yml — build verification + quality gates
stages:
- validate
- build
- test
- quality
- security
- deploy
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
validate:composer:
stage: validate
image: php:8.3-cli
script:
- composer validate --strict
- composer install --no-interaction --prefer-dist --no-progress
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
build:assets:
stage: build
image: node:26-bookworm
needs: ["validate:composer"]
script:
- npm ci
- npm run build
artifacts:
paths:
- public/build/
expire_in: 1 day
test:phpunit:
stage: test
image: php:8.3-cli
needs: ["build:assets"]
services:
- mysql:8.4
variables:
MYSQL_ROOT_PASSWORD: secret
DB_DATABASE: testing
script:
- cp .env.testing .env
- php artisan migrate --force
- vendor/bin/pest --parallel
coverage: '/^\s*Lines:\s*\d+\.\d+%/'
quality:coverage-gate:
stage: quality
image: php:8.3-cli
needs: ["test:phpunit"]
script:
- vendor/bin/pest --coverage --min=75
allow_failure: false
security:audit:
stage: security
image: php:8.3-cli
script:
- composer audit --locked
allow_failure: false
Use needs: to run independent gates in parallel. Pair that with build caching strategies so gates stay under five minutes on typical Laravel apps.
What quality gates should a Laravel project enforce in CI?
Laravel teams often under-test and over-trust php artisan serve locally. Production runs migrations, queues, scheduled tasks, and opcache—all absent on a laptop. Your gate set should reflect what actually breaks in production.
Minimum viable gate set
- Composer lock integrity — reject MRs that change
composer.jsonwithout an updated lockfile - PHP syntax and style — Laravel Pint or PHP-CS-Fixer on changed files only
- Static analysis — PHPStan level 5+ on
app/androutes/ - Automated tests — Pest or PHPUnit with an in-memory or containerised database
- Frontend build — Vite 8.x production build must succeed; see Vite vs Webpack for frontend builds
- Dependency audit —
composer auditfor known CVEs in locked packages
For deeper coverage policy, read code coverage gates in CI. Start at 60–70% line coverage on legacy code. Ratchet up 2–3 points per sprint rather than blocking every MR on day one.
Security gates worth the CI minutes
Secret leaks are the fastest way to turn a CI pipeline into an incident. Run Gitleaks or similar secret scanning on every push. Block high-severity composer audit findings on main.
SonarQube adds a unified quality gate for bugs, code smells, and security hotspots. Our SonarQube gate setup guide walks through threshold tuning. On budget-sensitive Nepal projects, start with free tooling—Pint, PHPStan, Pest, and composer audit—before adding hosted scanners.
# GitHub Actions equivalent — build verify + test gate
name: CI Quality Gates
on:
pull_request:
push:
branches: [main]
jobs:
build-verify:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
extensions: mbstring, pdo_mysql
coverage: xdebug
- run: composer install --prefer-dist --no-progress
- uses: actions/setup-node@v4
with:
node-version: "26"
- run: npm ci && npm run build
test-gate:
needs: build-verify
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
- run: composer install --prefer-dist
- run: cp .env.testing .env && php artisan key:generate
- run: vendor/bin/pest --coverage --min=70
Compare platform features in our GitHub Actions vs GitLab CI comparison. Both support required checks on protected branches—the enforcement layer that makes gates real.
How do build verification gates differ from deployment gates?
Build and test gates protect your repository. Deployment gates protect your users. Confusing the two leads to either slow MR feedback or fast broken production releases.
On projects I deploy with Deployer 7, the CI pipeline produces a verified artefact. The deploy stage—often manual on production—runs smoke checks after symlink swap. That is a deployment gate, not a build gate.
Blue-green or canary deploys add another gate layer. Traffic shifts only after health checks pass. See CI/CD blue-green deployment explained for the release-side pattern.
Reproducible builds matter here. If yesterday's green build differs from today's because a runner cached stale assets, your deploy gate validates the wrong thing. Lock Node and Composer versions and read why reproducible builds matter.
How do you fix failing quality gates without slowing down CI?
Teams abandon gates when pipelines exceed fifteen minutes and developers context-switch. Speed and strictness are not opposites if you design for both.
Make failures actionable
A gate that prints "test failed" without file and line number gets ignored. Pest and PHPUnit JUnit reports integrate with GitLab and GitHub MR annotations. PHPStan output should list the first ten errors, not ten thousand.
Store CI configs in-repo and validate YAML with a local linter or the JSON formatter and schema tools when generating dynamic pipeline JSON. Broken pipeline syntax blocks every gate at once.
Scope gates to changed code
Run full test suites on main nightly. On MRs, run affected tests plus a smoke subset. Tools like Pest parallel execution and path-filter rules in GitHub Actions cut feedback time sharply.
Allow allow_failure: true only during migration periods—and track removal in a ticket. Permanent soft gates train teams to ignore red pipelines.
Secrets and environment parity
CI failures often trace to missing env vars, not bad code. Use masked CI variables and follow CI/CD secrets management best practices. Match PHP extensions and MySQL version to production; PHP 8.3 locally and 8.5 on the runner causes false passes or false failures.
On a booking platform like Adventure Third Pole Trek, payment and availability tests belong in the mandatory gate set. A brochure site may defer coverage gates until traffic justifies the investment. Match gate strictness to business risk.
For Pest-specific setup, see Laravel testing with Pest in CI/CD. The GitHub Actions artifact attestation docs cover supply-chain verification if you ship container images.
Key Takeaways
- Build verification proves artefacts compile; quality gates enforce test, coverage, lint, and security policy before merge.
- Order CI stages cheapest-first and parallelise independent gates with
needs:to keep feedback under five minutes. - Protect main with required status checks—soft gates or retry-until-green culture defeats the entire purpose.
- Start with composer validate, tests, and
composer audit; add SonarQube and coverage ratchets incrementally. - Separate merge gates from deploy gates: smoke tests and manual approval belong on the release path, not every feature branch push.
- Document thresholds and bypass rules in CONTRIBUTING.md so gates stay predictable across the team.
People Also Ask
What is a quality gate in CI/CD?
A quality gate is an automated pass-or-fail checkpoint in a CI/CD pipeline. It runs defined checks—tests, lint, security scans, coverage diffs—and blocks promotion to the next stage when results fall below configured thresholds. Without enforcement on protected branches, a quality gate is only a warning.
What should fail a CI build?
At minimum: dependency install failure, compile or asset build failure, any failing test, lint errors on changed files, high-severity dependency vulnerabilities, and detected secrets in the diff. Optional gates include coverage drops, PHPStan level violations, and SonarQube quality profiles on mature codebases.
How is build verification different from testing?
Build verification confirms the project produces a runnable artefact—dependencies resolve, frontend assets compile, Docker images build. Testing validates behaviour against specifications. Both are gates, but build verification runs first because test jobs depend on a successful build stage.
Can quality gates slow down development?
Poorly designed gates do. Fast pipelines use caching, parallel jobs, and scoped checks on merge requests. Full suites run on main or on a schedule. A five-minute gate that prevents a two-hour production rollback is a net win for every team size.
Ship pipelines that enforce standards, not hope
Build Verification and Quality Gates in CI turn code review from the last line of defence into one layer among many. Start with build verify and tests this week. Add security scanning next. Ratchet coverage once the pipeline is stable and fast.
If your Laravel or PHP project still merges on trust alone, structured gate design saves more production hours than any single feature sprint. For hands-on pipeline setup, explore our testing and optimization services or custom software development work. Need a full audit of an existing pipeline? Contact us and we will map gates to your release risk.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

