🚀 Perfect for MVPs

Minimal SaaS

Essential features for rapid prototyping

Get from idea to deployed SaaS with AI assistance. Perfect for validating ideas quickly with a clean, functional foundation.

Simple Setup
Simple
MVP & Prototyping

What You Build in 45 Minutes

A complete, functional SaaS application ready for user testing and validation

Complete Next.js project with TypeScript
Supabase auth (sign up, sign in, password reset)
PostgreSQL database with type-safe queries
Tailwind CSS v3 with dark/light mode toggle
Form handling with validation
API routes with CRUD examples
Essential pages: homepage, auth, dashboard, settings
Single service setup (Supabase only)
Local development environment
Error logging and debug scripts

Simple, Focused Tech Stack

Only the essentials - no complexity, no bloat. Perfect for getting started quickly with proven technologies.

Frontend

4

Next.js with App Router

Server components with app router for optimal performance

TypeScript (Strict Mode)

100% type-safe development with strict TypeScript configuration

Tailwind CSS v3 (Pure)

Clean, simple Tailwind utilities with no component libraries

React Hook Form + Zod

Simple form handling with validation patterns

Auth

1

Supabase (Auth & Database)

Single service for authentication and PostgreSQL database

Database

2

Local Supabase Development

Full offline development with local Supabase service

Drizzle ORM

Type-safe database queries with migration system

Ready-to-Use Templates

Copy and customize these tested components for your project

Homepage

Complete homepage with hero section, features grid, and pricing

pages/homepage.tsx

Authentication Pages

Sign in and sign up pages with consistent styling

pages/signin.tsx & signup.tsx

Dashboard

Main dashboard with stats cards and onboarding checklist

pages/dashboard.tsx

Settings Page

Account settings with profile and billing sections

pages/settings.tsx

Dashboard Navigation

Simple nav bar with logo, links, and sign out button

components/dashboard-nav.tsx

Layouts

Marketing, auth, and dashboard layouts for consistent structure

layouts/*.tsx

4-Phase Setup Process

Follow the sequence for a complete minimal SaaS in under an hour

Phase 1: Foundation

Next.js project, TypeScript, environment setup, and dependencies

5 steps

Phase 2: Database & Auth

Supabase setup, Drizzle schema, migrations, and authentication

4 steps

Phase 3: UI

Tailwind setup, dark mode, marketing pages, and dashboard

4 steps

Phase 4: Features

API routes with CRUD operations and form validation

2 steps
Simple 4-phase setup process

Real Code Examples

See exactly what you get - production-ready components and patterns

Dashboard Navigation

Clean navigation component with dark mode support

TypeScript React
components/dashboard-nav.tsx
import Link from 'next/link'

export function DashboardNav() {
  return (
    <nav className="bg-white dark:bg-gray-950 border-b border-gray-200 dark:border-gray-800">
      <div className="max-w-6xl mx-auto px-4">
        <div className="flex justify-between items-center h-16">
          <div className="flex items-center space-x-8">
            <Link href="/dashboard" className="font-bold text-xl text-gray-900 dark:text-white">
              YourSaaS
            </Link>
            <Link 
              href="/dashboard" 
              className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
            >
              Dashboard
            </Link>
          </div>

          <div className="flex items-center space-x-4">
            <Link 
              href="/dashboard/settings"
              className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
            >
              Settings
            </Link>
            <button className="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white">
              Sign Out
            </button>
          </div>
        </div>
      </div>
    </nav>
  )
}

Drizzle Schema

Type-safe database schema with relations

TypeScript
lib/db/schema.ts
import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow()
})

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  published: boolean('published').default(false),
  userId: serial('user_id').references(() => users.id),
  createdAt: timestamp('created_at').defaultNow()
})

export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert

API Route with Validation

Type-safe API endpoint with Zod validation

TypeScript
app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { db } from '@/lib/db'
import { posts } from '@/lib/db/schema'

const createPostSchema = z.object({
  title: z.string().min(1).max(255),
  content: z.string().optional(),
  published: z.boolean().default(false)
})

export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const validatedData = createPostSchema.parse(body)
    
    const newPost = await db.insert(posts)
      .values(validatedData)
      .returning()
    
    return NextResponse.json(newPost[0])
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { error: 'Invalid data', details: error.errors },
        { status: 400 }
      )
    }
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    )
  }
}

Dark Mode Toggle

Simple theme switching with Tailwind classes

TypeScript React
components/theme-toggle.tsx
'use client'

import { useState, useEffect } from 'react'
import { Moon, Sun } from 'lucide-react'

export function ThemeToggle() {
  const [dark, setDark] = useState(false)

  useEffect(() => {
    const isDark = localStorage.getItem('theme') === 'dark' ||
      (!localStorage.getItem('theme') && 
       window.matchMedia('(prefers-color-scheme: dark)').matches)
    
    setDark(isDark)
    document.documentElement.classList.toggle('dark', isDark)
  }, [])

  const toggleTheme = () => {
    const newDark = !dark
    setDark(newDark)
    localStorage.setItem('theme', newDark ? 'dark' : 'light')
    document.documentElement.classList.toggle('dark', newDark)
  }

  return (
    <button
      onClick={toggleTheme}
      className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
    >
      {dark ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
    </button>
  )
}