Skip to content

StarknetPepe/shipkit

Repository files navigation

ShipKit — Next.js SaaS Starter

Ship your SaaS this weekend. Production-ready Next.js starter with auth, Stripe billing, dashboard, admin panel, and transactional email.

What's included

  • Auth: Email/password + Google OAuth via Better Auth. Session management, middleware protection.
  • Stripe billing: Subscriptions, checkout, customer portal, webhook handler with idempotency, dunning flow.
  • Dashboard: Dark-mode sidebar layout, responsive, ready for your product.
  • Admin panel: User management, stats (total users, paying, past_due, trial).
  • Billing settings: Current plan, manage billing button, invoice history with PDF links.
  • Dunning: In-app banner for failed payments, dunning email templates.
  • Landing page: Hero, features grid, pricing table, FAQ, footer.
  • Email: Resend integration with welcome, trial-ending, payment-failed, and recovery templates. Falls back to console logging if no API key set.
  • Feature gating: can(plan, feature) and isWithinLimit(plan, key, current) helpers.

Tech stack

Layer Tech
Framework Next.js 16 (App Router)
Language TypeScript
Styling Tailwind CSS v4
Auth Better Auth
Database Prisma + SQLite (dev) / Postgres (prod)
Payments Stripe
Email Resend
Deploy Vercel (one-click)

Quick start

# 1. Clone
git clone <your-repo-url> my-saas
cd my-saas

# 2. Install
npm install

# 3. Set up environment
cp .env.example .env.local
# Fill in your keys (see .env.example for details)

# 4. Set up database
npx prisma db push
npx prisma generate

# 5. Run
npm run dev
# Open http://localhost:3000

Stripe setup

  1. Create a free account at https://stripe.com
  2. Copy your test secret key from Dashboard → Developers → API keys
  3. Create Products and Prices in Dashboard (or use the seed script):
    npx tsx scripts/stripe-seed.ts
  4. Copy the printed price IDs to .env.local
  5. For webhooks, install Stripe CLI:
    stripe listen --forward-to localhost:3000/api/stripe/webhook
    # Copy the whsec_... to .env.local as STRIPE_WEBHOOK_SECRET

Project structure

src/
├── app/
│   ├── page.tsx                 # Landing page
│   ├── login/page.tsx           # Login
│   ├── signup/page.tsx          # Signup
│   ├── dashboard/
│   │   ├── layout.tsx           # Sidebar layout
│   │   └── page.tsx             # Dashboard
│   ├── settings/
│   │   ├── page.tsx             # Profile settings
│   │   └── billing/page.tsx     # Billing + invoices
│   ├── admin/page.tsx           # Admin panel
│   ├── pricing/page.tsx         # Pricing page (post-login)
│   ├── billing/success/page.tsx # Post-checkout confirmation
│   └── api/
│       ├── auth/[...all]/       # Better Auth handler
│       └── stripe/
│           ├── webhook/route.ts # Webhook handler
│           ├── checkout/route.ts# Create checkout session
│           └── portal/route.ts  # Customer portal redirect
├── components/
│   ├── sidebar.tsx              # Dashboard sidebar
│   └── dunning-banner.tsx       # Failed payment banner
└── lib/
    ├── auth.ts                  # Better Auth config
    ├── auth-client.ts           # Client-side auth hooks
    ├── auth-server.ts           # Server-side getSession()
    ├── db.ts                    # Prisma client
    ├── email.ts                 # Resend + email templates
    └── stripe/
        ├── plans.ts             # Pricing config (single source of truth)
        ├── can.ts               # Feature gating helpers
        └── checkout.ts          # Checkout session creation

Customizing

Change the brand

  • Edit ShipKit in src/components/sidebar.tsx and src/app/page.tsx
  • Update metadata in src/app/layout.tsx

Change pricing tiers

  • Edit src/lib/stripe/plans.ts — all UI reads from this config
  • Run scripts/stripe-seed.ts to create matching Products/Prices in Stripe

Add pages to the dashboard

  • Create files in src/app/dashboard/ — they inherit the sidebar layout
  • Add links to src/components/sidebar.tsx

Switch to Postgres for production

  • Change DATABASE_URL in .env.local to a Postgres connection string
  • Change provider = "sqlite" to provider = "postgresql" in prisma/schema.prisma
  • Run npx prisma db push

Deploy to Vercel

  1. Push to GitHub
  2. Import in Vercel
  3. Add all env vars from .env.example
  4. Deploy

For the webhook, add the production URL in Stripe Dashboard → Developers → Webhooks → Add endpoint:

  • URL: https://yourdomain.com/api/stripe/webhook
  • Events: checkout.session.completed, customer.subscription.*, invoice.*, charge.dispute.created, charge.refunded

License

Single-developer license. See LICENSE.md.

About

SaaS starter with Next.js, Stripe, Better Auth

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages