From Zero to Deployed: My SaaS Launch Checklist for Laravel Apps
There's a particular kind of dread that hits you about 48 hours before a SaaS launch. You've been heads-down building features, the demo looks great, your early adopters are excited — and then a quiet voice whispers: have you actually checked everything?
I've launched enough Laravel applications over the years to know that voice is worth listening to. Not because something will definitely go wrong, but because the things that do go wrong are almost always the same handful of things you forgot to check. The unsexy stuff. The stuff that isn't in any tutorial.
So I put together this checklist. I run through it before every production deployment now, and it's saved me from some genuinely embarrassing moments. I'm sharing it here in the hope it saves you from a few of your own.
1. Environment and Configuration
This sounds obvious, but you'd be surprised. Run php artisan config:cache and make sure nothing explodes. Then check:
APP_ENVis set toproductionAPP_DEBUGisfalse— seriously, double-check thisAPP_URLis your actual domain, notlocalhost- Your
.envfile is not in version control (check.gitignoreif you're unsure)
I also run php artisan about on production to get a quick snapshot of the environment. It's a handy command that Laravel quietly added and I still see developers who don't know about it.
2. Database and Migrations
Run php artisan migrate --pretend against your production database before running the real thing. It shows you exactly what SQL will execute. No surprises.
Also check:
- You have a backup strategy in place (not just "the host does it")
- Your indexes are appropriate for the queries your app runs
- Any seeders you're running in production are truly safe to re-run
If you're using something like PlanetScale or Neon for your database, make sure your connection pooling is configured sensibly. I've seen apps go down on launch day simply because the database ran out of connections under modest traffic.
3. Queue Workers and Scheduled Tasks
Queues are a classic one. Locally your jobs run fine. In production, nobody started the worker.
Make sure:
- Supervisor (or Laravel Octane, or whatever you're using) is configured and running
- Failed jobs have a notification set up — I use a simple Slack notification via
php artisan queue:failedmonitoring - Your
schedule:runcommand is registered in cron - Retry logic and timeouts are sensible for each job class
I wrote about queue gotchas in more depth in a previous post, but the short version is: always set $timeout and $tries explicitly on every job. Don't rely on defaults.
4. Payments and Billing Edge Cases
If you're charging money — and hopefully you are — test the unhappy paths, not just the happy ones.
Run through:
- What happens when a card is declined on signup?
- What happens when a subscription lapses and the user tries to access a paid feature?
- Are your webhook endpoints registered with Stripe/Paddle and returning
200correctly? - Have you tested the cancellation flow end-to-end?
I use Stripe with Laravel Cashier on most projects, and the webhook handling is genuinely excellent — but only if you've registered the routes and excluded them from CSRF protection properly. Check VerifyCsrfToken middleware. It catches people out more than it should.
5. Mail Configuration
Send a test email from production before you launch. Not from your local machine — from the actual production server.
Things to verify:
MAIL_FROM_ADDRESSis set to something people will recognise- SPF, DKIM, and DMARC records are configured for your sending domain
- Transactional emails (welcome, password reset, receipts) all render correctly
- You're not accidentally routing production mail through
logdriver
I nearly launched a client's app once with MAIL_MAILER=log. Everything looked fine in testing. You can imagine how that conversation would have gone.
6. Error Monitoring
You need to know when things break in production. APP_DEBUG=false means users won't see stack traces, which is good — but it also means you won't either, unless you're capturing errors somewhere.
I use Sentry on most projects, though Flare (built specifically for Laravel) is excellent and worth serious consideration. At minimum, make sure:
- Error reporting is connected and sending events
- You've set up an alert for error spikes
- 404s and 500s are distinguishable in your logs
7. Performance Basics
A few quick wins before you go live:
- Run
php artisan optimizeto cache config, routes, and views - Make sure Tailwind CSS is built for production (no development utilities, purged properly)
- Check your Lighthouse score on the marketing pages — first impressions matter
- Enable HTTP/2 on your server if you haven't already
With Tailwind CSS v4, the build output is already impressively lean, but it's still worth verifying the production build is what's being served and not a dev build that snuck through.
8. Security Basics
Not a full security audit, but the fundamentals:
- Run
php artisan key:generatehasn't been run after encrypting existing sessions (this would invalidate them all) - File permissions on
storage/andbootstrap/cache/are correct - Rate limiting is applied to login, registration, and API endpoints
- Sensitive routes are behind authentication middleware
Laravel's built-in security features are solid, but they only work if you actually use them.
The Night-Before Ritual
The evening before a launch, I open this checklist, make a coffee, and go through every item methodically. It takes maybe 45 minutes. And those 45 minutes have saved me from late-night panic more times than I can count.
Launching software is genuinely exciting. There's nothing quite like seeing real users sign up and start using something you built. Don't let something avoidable take the shine off that moment.
If you've got items you always check that aren't on this list, I'd love to hear them — drop me a message or find me on X. This list keeps growing, and that's a good thing.
Now go ship something.