What changes when the developer who writes the Laravel and React app also runs the pipeline that ships it.
I am the main developer on a Laravel 12 API with a React and Vite frontend. The repo has passed 3,000 commits. I also built and run the pipeline that ships it, the same template I use across 19+ repos.
Writing the app and deploying it are usually split between two people or two teams. When they are the same person, you feel every shortcut twice: once when you write it, and again when it breaks in production. Here are seven habits that came out of owning both sides.
- Tests run in CI, on every push
PHPUnit runs in GitHub Actions on every push. If the tests fail, the deploy step never starts.
This sounds obvious, but the important part is that it is automatic. Tests you run "when you remember" quietly stop being run. Tests that block the deploy keep getting fixed, because nothing ships until they pass.
Here is a simplified example of the shape of that workflow. Names and paths are placeholders:
name: test-and-deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
- run: composer install
- run: cp .env.example .env && php artisan key:generate
- run: php artisan test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Deploy over SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: cd /var/www/my-app && ./deploy.sh
The key line is needs: test. The deploy job cannot run unless the test job passed.
- Every product gets staging and live
Each product has a staging environment and a live environment. Staging is where I find the problem before a user does.
Staging only helps if it is close to live. Same pipeline, same deploy steps, just a different target. If staging is deployed by hand and live is deployed by CI, you are testing two different processes.
- Errors go to Sentry
The app reports errors to Sentry. A stack trace with the exact file, line and request is worth more than any bug report that says "it's not working."
When you also run the servers, this matters even more. You stop guessing whether a problem is in the code or the infrastructure, because the error tells you.
- Payment code gets no shortcuts
The app takes payments through Mollie. Payment code is where a small bug costs real money, so it never ships without CI passing.
The rule is simple: the more expensive a mistake is, the less room there is for "I'll test it later."
- Keep the split clear
Laravel API on the back, React and Vite on the front. A clear boundary between the two means that when something breaks, I know which side to open first.
- One deploy template, not one per project
I built one GitHub Actions template with SSH key deploys and Discord alerts. It runs across 19+ repos and 8 products, each with staging and live environments.
The benefit is not just less setup. When I improve the pipeline or fix a problem in it, I fix it once. One pipeline to maintain, not twenty slightly different ones.
- Let a bot nag you
Every repo has a PR bot that posts to Discord when a pull request has merge conflicts or has been sitting unmerged. Small problems get flagged while they are still small, instead of turning into a painful merge weeks later.
The real benefit
When you are the one who gets the alert, you start writing code that is easier to test, deploy and debug. None of these habits are complicated. They just stop being optional once you own the whole path from commit to production.
Top comments (0)