Laravel Deploy · 2025

How to Deploy Laravel to Production with Git Push (Under 5 Minutes)

Updated April 2025 · 10 min read

Complete Laravel production deployment: Composer, migrations, config:cache, and deploy hooks all automated.

HomeBlog › How to Deploy Laravel to Production with Git Push (Under 5 Minutes)

How to Deploy Laravel to Production with Git Push (Under 5 Minutes)

Deploying Laravel to a traditional shared hosting server involves cPanel, FTP, running composer install manually, wrestling with PHP version mismatches, and debugging obscure permission errors. It takes an hour on a good day.

With git-based deployment, the entire process — from git push to your Laravel app live at a URL — takes under 5 minutes. Here's exactly how.

What Git-Based Laravel Deployment Looks Like

The complete workflow, once configured:

# Make changes to your Laravel app
git add .
git commit -m "Add Stripe payment integration"
git push apexweave main
# Done — app is live with the new code in ~60-90 seconds

What happens automatically on the server:
1. New code is pulled from git
2. composer install --no-dev --optimize-autoloader runs
3. npm install && npm run build runs (if you have frontend assets)
4. Laravel's start command runs your app (PHP-FPM + Nginx)
5. Your post-deploy hook fires: php artisan migrate --force && php artisan config:cache && php artisan route:cache

No SSH. No manual commands. No forgotten steps.

Prerequisites

  • Laravel app working locally (php artisan serve works)
  • PHP 8.1+ (Laravel 11 requires PHP 8.2+)
  • Composer installed locally
  • Git installed locally
  • An ApexWeave account with a PHP app provisioned

Step 1: Prepare Your Laravel App for Production

1.1 Set up your .gitignore correctly

Laravel's default .gitignore is mostly correct, but verify these are excluded:

/vendor/
/node_modules/
.env
.env.backup
.env.production
/public/hot
/public/storage
/storage/*.key
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/.phpunit.result.cache

Never commit .env — this file contains your database password, app key, and API credentials. Use the hosting platform's environment variable management instead.

Never commit /vendor/ — Composer installs this on the server, in the correct environment for the server's PHP version and OS.

1.2 Ensure composer.json and composer.lock are committed

composer.lock must be committed. It pins exact package versions so the server installs the same dependencies you tested locally.

git add composer.json composer.lock
git commit -m "Add composer.lock for reproducible builds"

1.3 Generate your app key (for local dev only — production uses env var)

php artisan key:generate
# This writes APP_KEY to your .env — do NOT commit this

On production, you'll set APP_KEY as an environment variable.

1.4 Prepare your storage and bootstrap cache directories

These must be writable by the web server. Laravel's container image handles this automatically, but ensure your git repo doesn't accidentally include these directories:

# These should be in .gitignore:
/storage/logs/*
/storage/framework/cache/*
/storage/framework/sessions/*
/storage/framework/views/*
/bootstrap/cache/*

Keep the directories themselves (with .gitkeep files) but not their contents:

ls storage/framework/
# cache  sessions  testing  views — all should have .gitkeep, not actual files

Step 2: Configure PHP Version

Laravel 11 requires PHP 8.2+. Laravel 10 requires PHP 8.1+.

Set your PHP version on ApexWeave:

apexweave env:set your-app.apexweaveapp.com APEXWEAVE_STACK=php:8.3

Available: php:8.1, php:8.2, php:8.3 (default: php:8.3)

PHP 8.3 is the right choice for new Laravel projects — it's the fastest PHP version available and receives security updates until December 2027.

Step 3: Set Environment Variables

This is how you configure production-specific values without putting them in code or your git repository:

# App configuration
apexweave env:set your-app.apexweaveapp.com APP_ENV=production
apexweave env:set your-app.apexweaveapp.com APP_DEBUG=false
apexweave env:set your-app.apexweaveapp.com APP_KEY=base64:YOUR_APP_KEY_HERE
apexweave env:set your-app.apexweaveapp.com APP_URL=https://yourdomain.com

# Database (MySQL or PostgreSQL)
apexweave env:set your-app.apexweaveapp.com DB_CONNECTION=mysql
apexweave env:set your-app.apexweaveapp.com DB_HOST=dns.apexweaveapp.com
apexweave env:set your-app.apexweaveapp.com DB_PORT=3306
apexweave env:set your-app.apexweaveapp.com DB_DATABASE=your_database
apexweave env:set your-app.apexweaveapp.com DB_USERNAME=your_username
apexweave env:set your-app.apexweaveapp.com DB_PASSWORD=your_password

# Queue (if using queues)
apexweave env:set your-app.apexweaveapp.com QUEUE_CONNECTION=database
# or redis:
apexweave env:set your-app.apexweaveapp.com QUEUE_CONNECTION=redis
apexweave env:set your-app.apexweaveapp.com REDIS_URL=redis://:password@dns.apexweaveapp.com:6379

# Cache
apexweave env:set your-app.apexweaveapp.com CACHE_DRIVER=redis

# Mail
apexweave env:set your-app.apexweaveapp.com MAIL_MAILER=smtp
apexweave env:set your-app.apexweaveapp.com MAIL_HOST=smtp.mailgun.org
apexweave env:set your-app.apexweaveapp.com MAIL_USERNAME=your@mailgun.com
apexweave env:set your-app.apexweaveapp.com MAIL_PASSWORD=your-mailgun-password

# Stripe (if using payments)
apexweave env:set your-app.apexweaveapp.com STRIPE_KEY=pk_live_...
apexweave env:set your-app.apexweaveapp.com STRIPE_SECRET=sk_live_...

# Verify everything is set
apexweave env:list your-app.apexweaveapp.com

Generate your APP_KEY for production:

php artisan key:generate --show
# Outputs: base64:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
# Use this value for APP_KEY env var above

Step 4: Configure Build and Deploy Commands

In your ApexWeave dashboard → Settings → Build Configuration:

Install Command:

composer install --no-dev --optimize-autoloader

The --no-dev flag skips development dependencies (PHPUnit, Mockery, etc.) — reducing deployment size. --optimize-autoloader builds an optimised class map for faster autoloading.

Build Command (if using Laravel Mix or Vite):

npm install && npm run build

Start Command:
Leave blank for PHP apps — ApexWeave runs PHP-FPM with Nginx automatically for PHP apps.

Post-Deployment Hook:

php artisan migrate --force && php artisan config:cache && php artisan route:cache && php artisan view:cache

What each command does:
- migrate --force — runs pending database migrations (the --force flag is required for non-interactive production environments)
- config:cache — compiles all config files into a single file for faster loading (replaces 100+ small config reads with one)
- route:cache — compiles the route list for faster routing
- view:cache — compiles all Blade templates

These caching commands are critical for Laravel production performance. Without them, every request re-reads config files and re-compiles routes.

Step 5: Add ApexWeave Remote and Deploy

# Add ApexWeave as a git remote
git remote add apexweave https://git.apexweaveapp.com/your-username/your-app.git

# Push code and trigger deployment
git push apexweave main

# Watch the deployment
apexweave deploy your-app.apexweaveapp.com --follow

Expected output:

Pulling commit: 5a3c1d8
Running: composer install --no-dev --optimize-autoloader
Loading composer repositories...
Installing dependencies from lock file
Generating optimised autoload files
Running: npm install && npm run build
...built successfully
Running post-deployment hook:
  php artisan migrate --force
  Migrating: 2025_04_01_000001_create_orders_table
  Migrated: 2025_04_01_000001_create_orders_table (23ms)
  php artisan config:cache
  Configuration cache cleared!
  Configuration cached successfully!
  php artisan route:cache
  Route cache cleared!
  Routes cached successfully!
  php artisan view:cache
  Blade templates cached successfully!
Health check: 200 OK
Deployment complete (78 seconds)

Step 6: Verify the Deployment

# Check app responds
curl https://your-app.apexweaveapp.com

# View application logs
apexweave logs your-app.apexweaveapp.com

# Stream live logs
apexweave logs your-app.apexweaveapp.com --follow

# Access container shell for debugging
apexweave bash your-app.apexweaveapp.com

# Check environment variables are available inside container
apexweave bash your-app.apexweaveapp.com
echo $APP_KEY
php artisan env

Step 7: Run Database Seeders (First Deployment Only)

For initial data setup:

apexweave run "php artisan db:seed" your-app.apexweaveapp.com

For specific seeders:

apexweave run "php artisan db:seed --class=RolesAndPermissionsSeeder" your-app.apexweaveapp.com

Step 8: Set Up Custom Domain

apexweave domain:set your-app.apexweaveapp.com yourdomain.com

At your DNS provider:
- Add A record: @ → your ApexWeave server IP (shown in dashboard)
- Add A record: www → same IP (or CNAME wwwyourdomain.com)

SSL auto-provisions within minutes. Update your APP_URL environment variable:

apexweave env:set your-app.apexweaveapp.com APP_URL=https://yourdomain.com

Then trigger a redeploy so the config cache picks up the new URL:

git commit --allow-empty -m "Update APP_URL"
git push apexweave main

Laravel Queue Workers in Production

If your Laravel app uses queues (emails, notifications, background jobs), you need a queue worker running continuously.

Option 1: Configure queue worker as part of start command

Create a Procfile-style configuration. In your ApexWeave Start Command, you can use a process supervisor. The recommended approach is to use supervisor via a post-deployment script, or configure it via your docker-compose.yml if using Docker.

For simpler queue requirements, run queues via a cron job approach:

Option 2: Use scheduled commands for lightweight queuing

Add to your app/Console/Kernel.php:

$schedule->command('queue:work --max-time=60 --stop-when-empty')->everyMinute();

And add the Laravel scheduler to run via a deploy hook or cron-equivalent.

Option 3: Use database driver and process via deploy hooks

For low-volume queue needs:

# In post-deployment hook, process pending jobs:
php artisan queue:work --once --tries=3

For production queues at scale, a dedicated queue worker process on a separate service is the right approach.

Handling File Uploads in Laravel Production

Never store uploaded files in storage/app/public/ on a container-based deployment. Container filesystems are ephemeral — files written to disk are lost on redeploy.

Configure S3 (or any S3-compatible storage) for file uploads:

Environment variables:

apexweave env:set your-app.apexweaveapp.com FILESYSTEM_DISK=s3
apexweave env:set your-app.apexweaveapp.com AWS_ACCESS_KEY_ID=AKIA...
apexweave env:set your-app.apexweaveapp.com AWS_SECRET_ACCESS_KEY=xxx
apexweave env:set your-app.apexweaveapp.com AWS_DEFAULT_REGION=us-east-1
apexweave env:set your-app.apexweaveapp.com AWS_BUCKET=your-bucket-name

In your Laravel code:

// Store file in S3
Storage::put('uploads/' . $filename, $file);

// Get public URL
$url = Storage::url('uploads/' . $filename);

Common Laravel Production Deployment Issues

500 Internal Server Error after deployment

Most common cause: Missing environment variable.

Debug:

apexweave logs your-app.apexweaveapp.com
# Look for: "Undefined variable: ..." or "No application key"

Ensure APP_KEY is set and APP_DEBUG=false in production (debug mode can also mask errors — set to true temporarily to see the actual error message).

Migration fails during deployment

Cause: Migration contains a data change that conflicts with existing data, or a foreign key constraint issue.

Debug:

apexweave bash your-app.apexweaveapp.com
php artisan migrate --pretend   # shows SQL without executing
php artisan migrate:status       # shows which migrations have/haven't run

Class not found / Autoloader issues

Cause: Composer autoload not optimised, or a new class isn't in the autoload map.

Fix:

apexweave run "composer dump-autoload --optimize" your-app.apexweaveapp.com

Or trigger a fresh deployment which runs composer install --optimize-autoloader.

Views not updating after deployment

Cause: View cache is stale.

Fix: Add php artisan view:clear before php artisan view:cache in your post-deployment hook:

php artisan view:clear && php artisan view:cache

"Whoops, looks like something went wrong" in production

Cause: APP_DEBUG=false hides error details for security. This is correct — your users should never see stack traces.

Debug:

apexweave logs your-app.apexweaveapp.com
# Laravel logs detailed errors even when debug=false

Or temporarily enable debug (in non-production testing only):

apexweave env:set your-app.apexweaveapp.com APP_DEBUG=true
# Redeploy, reproduce error, note the details
apexweave env:set your-app.apexweaveapp.com APP_DEBUG=false
# Redeploy to restore security

Ongoing Deployment Workflow

After initial setup, every code change follows this pattern:

# Develop locally
php artisan make:controller PaymentController
# ... write code ...

# Test locally
php artisan test

# Deploy to production
git add .
git commit -m "Add PaymentController for Stripe integration"
git push apexweave main

# Monitor deployment
apexweave deploy your-app.apexweaveapp.com --follow

# Check logs after deployment
apexweave logs your-app.apexweaveapp.com

Rollback if something breaks:
Go to your ApexWeave dashboard → Logs tab → find the last working deployment → click Rollback. Your app returns to that commit's state in under 30 seconds.

Complete Laravel Production Checklist

Before your Laravel app goes live:

  • [ ] APP_ENV=production
  • [ ] APP_DEBUG=false
  • [ ] APP_KEY set as environment variable (not in code)
  • [ ] Database credentials set via env vars
  • [ ] /vendor/ and .env in .gitignore
  • [ ] composer.lock committed
  • [ ] Post-deploy hook: migrate --force && config:cache && route:cache && view:cache
  • [ ] File uploads configured to use S3 (not local storage)
  • [ ] HTTPS enforced (https:// in APP_URL)
  • [ ] Queue connection configured for production (database or Redis, not sync)
  • [ ] Log channel configured for production (stack or errorlog)
  • [ ] Error reporting to Sentry or similar (optional but recommended)
  • [ ] Health check endpoint for monitoring

Deploy your Laravel app at apexweave.com/git-deployment.php — PHP 8.3, automatic Composer installs, deploy hooks, and database management included.

Deploy Your App with Git Push

Automatic builds, environment variables, live logs, rollback, and custom domains. No server management required.

Deploy Free — No Card Required

Powered by WHMCompleteSolution