DEV Community

FileShot
FileShot

Posted on

What actually goes into a production-ready SaaS boilerplate (hint: it's not just auth)

Every developer who's shipped a SaaS product has had the same moment: you stare at a blank repo and think "I'll just wire up auth real quick." Three weeks later you're still fighting OAuth redirect URIs, forgetting to hash passwords correctly, and trying to remember if you added rate limiting to the login endpoint.

Auth is the obvious starting point. But it's not the hard part.

What people miss when they think about "production-ready"

Here's a non-exhaustive list of what a real production SaaS needs beyond auth:

Payments that don't break
Stripe webhooks are notoriously tricky. You need idempotency keys, signature verification on every incoming webhook, retry handling, and logic for subscription states: trialing, active, past_due, canceled. Miss any of these and you'll have users who upgraded but still see the free tier — or get double-charged.

API rate limiting
Every public endpoint needs it. Not just "limit to 100 req/minute globally" — per-user, per-endpoint rate limiting with proper 429 responses and Retry-After headers.

Email infrastructure
Transactional emails (password reset, invoice receipt, account confirmation) need to actually deliver. That means a proper SMTP provider, SPF/DKIM records, and templates that render in Outlook circa 2019.

Proper session management
JWTs with sensible expiry, refresh token rotation, revocation on logout. If you're storing sessions in a cookie, make sure it's HttpOnly, Secure, and SameSite=Strict.

API keys for programmatic access
If you're building anything developer-facing, users will want API keys. That's a whole sub-system: key generation (don't store raw keys — hash them), scopes/permissions, revocation, usage tracking.

Two-factor authentication
TOTP-based 2FA (Google Authenticator, Authy) with proper backup codes. Not optional for anything handling real user data.

Database migrations
Not "I'll just alter the table in prod" — a versioned, idempotent migration system that can run on deploy without downtime.

Docker + deployment config
An actual Dockerfile, not just "it works on my machine." Environment variable management, health check endpoints, graceful shutdown handling.

Why this is hard to get right the first time

Each of these subsystems has its own set of edge cases, and they interact with each other. Your rate limiter needs to know who the user is (auth integration). Your Stripe webhooks need to update your database (migration dependency). Your 2FA backup codes need to be hashed (same as API keys).

Getting all of this right from scratch takes weeks and usually results in at least a few security mistakes along the way.

What I've been building

I got tired of rebuilding the same scaffolding for every project, so I built DiggaByte Labs — a SaaS boilerplate marketplace where you pick exactly the stack modules you need and download a production-ready codebase built around those choices.

The idea is: instead of a "starter template" that's just an opinionated file structure, you get code that's actually wired together. Stripe webhooks already talk to your database. Rate limiting is already in the middleware chain. The 2FA flow already works end-to-end.

The current stack selections include: PostgreSQL + Prisma, JWT auth, Google OAuth, GitHub OAuth, Stripe subscriptions, shadcn/ui, rate limiting, API keys, 2FA, and Docker deployment.

The checklist I use before calling anything "production-ready"

Before shipping any SaaS, I go through this:

  • [ ] All passwords bcrypt-hashed (cost factor 12+)
  • [ ] JWT secret is 256-bit random, not a dictionary word
  • [ ] Refresh tokens rotate on use, invalidate on logout
  • [ ] Stripe webhook signature verified on every event
  • [ ] Rate limiting on auth endpoints (login, password reset, 2FA)
  • [ ] API keys hashed in DB (store only the last 4 chars for display)
  • [ ] 2FA backup codes are one-time-use and hashed
  • [ ] SQL queries use parameterized statements (no string concatenation)
  • [ ] Environment variables never logged
  • [ ] HttpOnly + Secure + SameSite on all auth cookies
  • [ ] Health check endpoint at /health returns 200 with no sensitive info
  • [ ] Graceful shutdown: drain connections before process.exit

If any of those are unchecked in your codebase, that's the real work.

Happy to answer questions about any of these in the comments — particularly the Stripe webhook setup and the API key hashing pattern, which I see done incorrectly in the wild constantly.

Top comments (0)