What I Learned Deploying a T3 stack with Laravel Forge
What I Learned While Deploying a T3 stack app called KidCheckIn with Laravel Forge
Today was a huge milestone in building KidCheckIn. I deployed the site through Laravel Forge. It wasn’t smooth, but it was solid. I hit a bunch of errors, rolled up my sleeves, and pushed through until everything worked the way it was supposed to. Honestly, I learned more from today’s struggles than from weeks of tutorials.
Here’s what went down and what I picked up along the way.
The Build Process Taught Me to Respect Linting
My first blocker was a wave of lint errors that hit when I tried to deploy. I had skipped over them before, thinking they were just minor style things. But today, I realized that linting isn’t just about formatting, it can break your build if you ignore it.
I fixed each lint issue one by one, ran pnpm lint, fixed what was necessary, and then built locally with:
pnpm build
Lesson learned: Don’t ignore linting, especially when you’re deploying to production.
Writing a Deployment Script for Forge
To make the whole deployment process smoother, I wrote a custom Bash deployment script for Forge. Here’s a snapshot of what it does:
#!/bin/bashcd /home/forge/kidcheckin.com git pull origin t3-kidcheckin
export NODE_ENV=production pnpm install pnpm build pnpm drizzle-kit push
pm2 delete kidcheckin || true pm2 start "pnpm start" --name kidcheckin --watch
pm2 save
This script pulls the latest code, installs dependencies, builds the app, pushes Drizzle migrations, and restarts the app with PM2. Now I can hit deploy in Forge or push to GitHub and let this script handle the rest.
Nginx and SSH: Facing the Scary Stuff
Nginx config used to feel like a black box, but I got hands-on today and it finally clicked. I made sure my site was pointing to the right .output directory from the Next.js build:
nginx Copy Editlocation / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }
I also SSH’d into the Forge server, set up PostgreSQL, and created the database .
Once that was done, I connected it all through .env and tested locally before going live.
Quick Deploy + GitHub Auto-Deploy
One of the coolest things I set up today was Quick Deploy through Forge. Once the deployment script was working, I linked it to my GitHub repo and enabled automatic deployment from the t3-kidcheckin branch. Now whenever I push changes, Forge picks it up and runs the whole process for me.
I tested it by making a small update, pushing to GitHub, and boom — it deployed live without me touching a thing.
Wrapping It Up
Today stretched me. I got frustrated, had to Google way too many things, and felt like I broke the site more than I fixed it. But by the end, I had:
- Fixed my build process
- Written a working deployment script
- Configured Nginx with confidence
- Set up and connected PostgreSQL on a live server
- Enabled auto-deploy from GitHub
It’s wild how much you can learn from just sitting down and doing the thing. KidCheckIn is one step closer to being ready for Sundays.
Published April 24, 2025