Skip to main content

When to Outgrow Your SaaS Boilerplate in 2026

·StarterPick Team
saas-boilerplatescalingrefactoringarchitecture2026opinion

Every Boilerplate Has an Expiration Date

A SaaS boilerplate is a starting point, not a final destination. It's designed to get you from zero to first customer quickly. But as your product grows, the assumptions baked into that boilerplate start to constrain you.

This is not a failure of the boilerplate — it's a sign your product has succeeded. The question is: when do you stop working within the boilerplate and start working around it?


Signs You've Outgrown Your Boilerplate

1. You're fighting the auth system

// Early stage: boilerplate auth is sufficient
const session = await auth();
const user = session?.user;

// Growth stage: you need things the boilerplate doesn't support
// - Custom JWT claims for RBAC
// - Organization-level permissions
// - SSO / SAML for enterprise customers
// - Device fingerprinting for security
// - Custom session storage

// Symptom: You've patched auth.ts so many times it's
// unrecognizable from the original

What to do: If Auth.js doesn't support what you need, migrate to Clerk (managed) or Better Auth (flexible). Don't hack auth — it's the most security-critical part of your stack.

2. Your database schema is radically different from the original

// Original boilerplate schema:
model User {
  id        String @id
  email     String @unique
  plan      String
}

// Your schema after 18 months:
model User {
  id                    String   @id
  email                 String   @unique
  // 40+ additional fields
  organizationId        String?
  role                  UserRole
  customDomain          String?
  apiRateLimit          Int
  stripeCustomerId      String?
  stripeSubscriptionId  String?
  svixAppId             String?
  usageTokensThisMonth  Int
  // ... etc
}

When your schema differs this significantly from the original, the boilerplate's auth helpers, billing hooks, and admin queries no longer match your data model. You're maintaining parallel systems.

What to do: This is healthy growth — it means you've built a real product. Document the divergence. Stop trying to reconcile with upstream updates.

3. You need infrastructure the boilerplate doesn't have

Boilerplate provides: Serverless functions on Vercel

You now need:
  - Background workers (email processing, data pipelines)
  - WebSocket servers (real-time collaboration)
  - Message queues (event-driven processing)
  - Dedicated compute (ML model inference)
  - Multi-region deployment

Symptom: You're deploying services outside the boilerplate
framework and the app isn't coherent anymore

What to do: Add services as needed (Railway worker service, Inngest for jobs). The boilerplate becomes the web layer, not the entire app.

4. Your performance requirements exceed the default architecture

// Boilerplate default: every request hits the database
export default async function ProductList() {
  const products = await db.product.findMany();
  return <Products data={products} />;
}

// At scale (100K+ users, 10K+ products):
// You need: Redis caching, CDN, read replicas, cursor-based pagination
// None of which are in the boilerplate

// Symptom: Database CPU at 90%, page load >3s, Vercel function timeouts

What to do: Add caching (Upstash Redis), optimize queries, add indexes. These are architectural additions, not replacements of the boilerplate.

5. The boilerplate is actively blocking features you need

// Boilerplate assumes single-tenant users
// You need multi-tenant organizations
// → Had to rewrite auth context, billing logic, API design

// Boilerplate uses Prisma with PostgreSQL
// You need sharding for a specific data type
// → Fighting the ORM to support your access patterns

// Boilerplate uses a specific email provider
// Your enterprise customers require SES + custom SMTP
// → Abstraction layer doesn't support it

When the boilerplate assumptions actively prevent features customers are requesting, you've crossed the line from "working with" to "working around."


What You Should Never Rewrite

Before you consider a full rewrite, be honest about what the boilerplate actually provides that you'd have to rebuild:

Stripe webhook handling:

// This looks simple but has 6 edge cases:
// 1. Signature verification
// 2. Idempotent event processing
// 3. Subscription state machine (active → past_due → canceled)
// 4. Dunning flow (retry failed payments)
// 5. Plan change proration handling
// 6. Trial period management

// Time to rebuild correctly: 2-4 weeks
// Time to break: 30 minutes of reckless editing

Auth session management: The boilerplate handles CSRF protection, secure cookie settings, session rotation, and token refresh. These are easy to get wrong and hard to debug.

Email delivery: Bounce handling, unsubscribe compliance, transactional vs marketing separation. The boilerplate's email integration gets this right by default.


The Migration Spectrum

You don't have to choose between "keep the boilerplate as-is" and "rewrite from scratch." There's a spectrum:

Level 1: Extend with new services

When: Need background jobs, WebSockets, or storage that Vercel doesn't provide. Action: Deploy additional services (Railway worker, S3, Upstash) alongside the boilerplate app. Disruption: Minimal. The boilerplate web layer stays intact.

Level 2: Replace individual subsystems

When: Auth system doesn't meet requirements, billing logic is too different. Action: Replace auth module with Clerk or Better Auth. Replace billing hooks with custom implementation. Disruption: Moderate. Other parts of the boilerplate still work.

Level 3: Extract to a service

When: A specific domain (notifications, file processing, AI pipeline) needs its own deployment. Action: Extract to a separate service with its own database tables and API. Disruption: Moderate. Main app calls the service via API.

Level 4: Full architectural migration

When: The entire data model, deployment model, or tech stack needs to change. Action: Build the new architecture in parallel, migrate users gradually. Disruption: High. Essentially a rebuild.

Level 4 is almost always the wrong choice. Products that do level 4 typically underestimate the work by 5-10x.


The Refactoring Signals

How do you know which level you need?

"We can't ship feature X because of the boilerplate" → Level 2-3
  Is it auth? → Level 2 (replace auth module)
  Is it infrastructure? → Level 1-3 (add service)
  Is it the entire data model? → Level 3-4 (extract domain)

"The boilerplate code is slowing us down" → Usually Level 1-2
  Specific files are messy → Refactor those files
  Entire architecture is wrong → Level 3-4 (rare and expensive)

"Enterprise customers need X" → Level 2-3
  SSO/SAML → Replace auth (Level 2)
  Custom data isolation → Extract tenant service (Level 3)
  On-premise deployment → Architecture migration (Level 4)

When to Start Fresh

Starting fresh is justified when:

  1. Your tech stack is fundamentally wrong for your scale. You need PHP/Elixir/Go for performance and the JavaScript stack is the bottleneck — not just slow code.

  2. The boilerplate has security issues you can't patch. Not theoretical — actual CVEs that require architectural changes.

  3. A major acquisition or pivot requires a different codebase. Business reasons override technical continuity.

  4. The team has grown beyond the original architecture's capacity. 20+ engineers working in a monolith designed for 1-2 developers causes organizational friction that's as real as technical debt.

Note: "We don't like the boilerplate's style" is not a valid reason. Refactor incrementally.


The Right Boilerplate Transition

If you do decide to adopt a different boilerplate or rebuild:

  1. Never big-bang migrate. Run both systems in parallel.
  2. Migrate the simplest components first. Don't start with auth or billing.
  3. Keep the database as the source of truth. Both systems can read the same tables during transition.
  4. Set a deadline. Open-ended parallel systems are technical debt that lasts years.

Conclusion

Most SaaS products don't outgrow their boilerplate — they outgrow specific assumptions the boilerplate made. The answer is almost always surgical replacement of those assumptions, not a full rewrite.

Respect what the boilerplate got right. Build on top of what works. Replace only what genuinely constrains you.

StarterPick helps you choose a boilerplate with the right architectural assumptions for your product's eventual scale — so you outgrow it later rather than sooner.

Comments