The 6-Week Constraint Is a Feature, Not a Bug
I have built SaaS products that took 6 months and SaaS products that took 6 weeks. The 6-month ones were not more successful. In fact, the fastest ones often outlasted the methodically built ones because they reached paying customers before the market moved. The 6-week timeline forces discipline: you cannot gold-plate the architecture, you cannot add every feature someone requested in a Slack thread, and you cannot spend a week debating whether to use Redux or Zustand.
The constraint produces clarity. Every decision gets made against a single criterion: does this help us ship a working product that someone will pay for within six weeks? If the answer is no, it does not make it into the first version. This is not laziness — it is the most important engineering discipline for early-stage products.
The Stack I Use Every Time
I stopped experimenting with my stack two years ago. Experimentation during client projects introduces unnecessary risk. The stack I use — Next.js 15 App Router, FastAPI, PostgreSQL with Drizzle ORM, Clerk for auth, Stripe for billing, Railway for deployment — is boring in the best possible way. Every piece is proven, well-documented, and has a clear upgrade path.
Frontend: Next.js 15 with TypeScript, Tailwind CSS, and shadcn/ui for components. The App Router with Server Components dramatically reduces the amount of client-side JavaScript you ship, which means better performance without manual optimization. shadcn/ui gives you accessible, copy-paste components that you own — no npm package to update, no version conflicts, no upgrade friction.
Backend: FastAPI with Pydantic v2 for request/response validation, SQLAlchemy 2.0 as the ORM (I use the async session variant), Alembic for migrations, and PostgreSQL on Railway. The entire backend follows a simple pattern: router → service → repository. No overengineered domain-driven design for an MVP. Three layers, clean separation, easy to test.
Key insight: The biggest time sink in SaaS development is not coding — it is making architectural decisions under pressure. Committing to a fixed stack before the project starts eliminates that entire category of delay.
Week-by-Week Breakdown
The timeline is not aspirational — it is the actual schedule I follow on every engagement, enforced by a fixed-price contract that creates accountability on both sides.
Week 1: Foundation
Database schema, authentication, and project scaffolding. By end of week 1, a user can sign up, log in, and see an empty dashboard. The schema is designed for the final product, not just the MVP — changing it mid-project is expensive. I spend extra time here because a wrong data model costs 10x more to fix in week 4 than in week 1.
# FastAPI project structure — enforced from day one
app/
routers/ # HTTP layer only — no business logic
auth.py
users.py
billing.py
services/ # Business logic — no HTTP, no DB
user_service.py
billing_service.py
repositories/ # DB access only — no business logic
user_repo.py
models/ # SQLAlchemy models
schemas/ # Pydantic request/response schemas
core/
config.py # Settings from environment
database.py # Async engine + session factory
security.py # JWT verification
Week 2: Core Feature #1
Whatever the primary value proposition is, it gets built this week. For a document analysis tool, that is the upload + AI processing pipeline. For a project management tool, that is task creation and assignment. This is the thing that makes someone willing to pay, so it gets the most attention and the most testing.
Week 3: Billing Integration
Stripe integration is always week 3 — early enough that it is tested thoroughly, late enough that you know the product is real. The integration uses Stripe Checkout for the payment flow (zero custom payment UI to build or maintain), Stripe Customer Portal for subscription management, and webhooks for synchronizing subscription state to your database.
// app/api/stripe/webhook/route.ts
import Stripe from "stripe";
import { headers } from "next/headers";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const body = await req.text();
const signature = headers().get("stripe-signature")!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch {
return new Response("Webhook signature verification failed", { status: 400 });
}
switch (event.type) {
case "customer.subscription.created":
case "customer.subscription.updated":
await syncSubscription(event.data.object as Stripe.Subscription);
break;
case "customer.subscription.deleted":
await cancelSubscription(event.data.object as Stripe.Subscription);
break;
}
return new Response(null, { status: 200 });
}
Weeks 4-5: Polish and Secondary Features
Error states, loading states, empty states, onboarding flow, email notifications (Resend), and the second core feature if the timeline allows. Most of the UX quality that makes the difference between "this feels like a real product" and "this feels like an MVP" lives in these two weeks. Do not skip them in a rush to add features.
Week 6: Deployment and Hardening
Production deployment on Railway, environment variable audit, error monitoring setup (Sentry), analytics (PostHog), and a staged rollout. The client gets a 30-minute training session and a handoff document. Soft launch to the first 10 users, then iterate based on real feedback.
What Not to Build in Week 1
The features that kill MVP timelines are always the same: complex role-based permissions (build simple admin/user roles), real-time collaboration (polling is fine for v1), custom analytics dashboards (use PostHog), multi-tenancy with data isolation (single-tenant first), and mobile apps (responsive web only). Every one of these can be added in v2 when you have paying customers and revenue to fund the work.
Clients often push back on this list. The right response is: "If we build all of this now and nobody wants the product, we have wasted 3 months. If we ship in 6 weeks and 100 people pay, we can build everything on this list funded by their subscriptions." That conversation has never failed to bring alignment.