Preview environments for standalone Laravel
A Laravel app is far more than php artisan serve. Every branch gets the whole runtime on its own managed VPS — queues draining, Horizon supervising, the scheduler ticking, a seeded database and mail caught instead of sent — behind a real HTTPS URL.
- ✓ Queues & Horizon
- ✓ Scheduler running
- ✓ Mail caught, not sent
A Laravel app is more than a web process
Most preview tools boot a single HTTP process and call it done. But the behaviour you actually need to review — a job that fires after checkout, a nightly report, a welcome email, a cache that warms — lives in everything around the web process. Leave those out and the preview lies to you.
A bare web process renders pages, but queued jobs pile up unworked, scheduled tasks never run, and mail silently fails. Reviewers approve a PR that’s broken in every async path.
Workers drain the queue, the scheduler fires schedule:work, mailables are captured for inspection, and the database is migrated and seeded — so what a reviewer sees is what production does.
Everything Laravel expects, provisioned for you
Each branch boots a complete Laravel runtime on a dedicated VPS — not a stub, not a subset. These are the pieces a real review depends on.
Queues & Horizon
A live worker drains jobs as they’re dispatched. Run plain queue:work or the full horizon supervisor with its dashboard, retries and failed-job table.
The scheduler, ticking
schedule:work runs alongside the app, so cron-driven commands, digests and cleanup tasks actually fire on the branch — not just in your Kernel.
Mail, caught
A built-in SMTP catcher intercepts every mailable. Inspect the rendered email instead of risking a real send to a customer’s inbox.
Cache & Redis
Redis is provisioned per environment for cache, sessions, rate limiting and queues — so cache tags, locks and atomic operations behave exactly as deployed.
Storage & disks
The local and public disks and the storage symlink are ready on boot; S3-style disks resolve from project secrets you provide.
Matched PHP & extensions
Your declared PHP version and required extensions run in the container, so a bug that needs bcmath, gd or a specific patch release reproduces faithfully.
The commands you’d run by hand, automated
You declare install, migrate and process commands once. We run them in clean containers on every push — composer for the app, a worker, the scheduler, no CI YAML to babysit.
# build — runs on every push to the branch composer install --optimize-autoloader php artisan migrate --seed # isolated MySQL/Postgres, real data # long-running processes, supervised per environment php artisan horizon # or: php artisan queue:work php artisan schedule:work # cron, in-process ✓ ready https://acme-billing-api.admn.cloud
From a pushed branch to a working runtime
- 01
Declare the runtime
Set your PHP version, install and migrate commands, the database engine and which worker the app should run — your queue:work, Horizon and scheduler processes.
- 02
Push a branch
We provision a dedicated VPS, run your build in a container, create and seed an isolated database, and start every declared process under supervision.
- 03
Review the real thing
Open the HTTPS URL, watch jobs drain, read caught mail, run Artisan or Tinker against it. Renew the lease to keep it, or let it expire and tear down clean.
Laravel preview environments, answered
Does Horizon run, or just a plain queue worker?
Both are supported — you choose in your declared commands. Point a process at `php artisan queue:work` for a simple worker, or run `php artisan horizon` to get the full Horizon supervisor with its dashboard at /horizon. Because Redis is provisioned per environment, Horizon’s metrics, tags and failed-job tooling all behave exactly as they do in production.
Is Octane or FrankenPHP supported?
Yes. The app runs from your build commands inside a container, so if your stack uses Octane you can boot it with `php artisan octane:start --server=frankenphp` (or Swoole/RoadRunner) as the web process instead of php-fpm. We don’t force a server choice — whatever your declared start command is, that’s what serves the preview.
MySQL or Postgres — and is it actually seeded?
Either. Each environment gets its own isolated database of the engine you pick, and we run `php artisan migrate` followed by your seeders on first boot, so reviewers land on realistic data rather than an empty schema. The database is created and destroyed with the environment — nothing is shared with staging.
Does mail actually send, or is it caught?
Caught, never sent. Every environment ships with a built-in SMTP catcher and MAIL_MAILER wired to it, so password resets, notifications and queued mailables are captured and viewable instead of hitting real inboxes. You can review the rendered HTML of any message without risking a single email reaching a customer.
What about storage and S3 disks?
The `local` and `public` disks work out of the box on the environment’s own filesystem, and the storage symlink is created for you. For S3-style disks you provide credentials as project secrets — point them at a real bucket, or at a per-environment prefix, and the `s3` disk resolves them like any other env-driven config.
Can I run Artisan commands or open Tinker against a preview?
Yes. Every environment exposes a shell into the running app container, so you can run any `php artisan` command, drop into `php artisan tinker`, inspect logs or re-run a seeder against the live preview database — useful for reproducing a reviewer’s bug without rebuilding anything locally.
Give every Laravel PR a runtime, not a guess
Connect GitHub and get the full Laravel stack per branch — queues, scheduler, seeded DB and caught mail — for $15/mo flat plus metered usage. Unlimited projects and seats.
