Skip to main content

Customize ShipFast for Your Specific SaaS Idea 2026

·StarterPick Team
shipfastcustomizationnextjsguide2026

TL;DR

ShipFast is designed to be modified, not extended. The source is yours — clone it, customize it, own it. The most common customizations are: adding teams/organizations, swapping the email provider, changing pricing structure, and adding a blog. This guide covers the 5 most requested ShipFast customizations with actual code.


Customization 1: Changing the Color Scheme

ShipFast uses Tailwind CSS with DaisyUI. Brand customization starts here:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        // Override the default brand colors
        primary: '#6366f1',      // Your primary color
        'primary-focus': '#4f46e5',
        'primary-content': '#ffffff',
      },
    },
  },
  plugins: [
    require('daisyui'),
  ],
  daisyui: {
    themes: [
      {
        light: {
          ...require('daisyui/src/theming/themes')['light'],
          primary: '#6366f1',
          'primary-focus': '#4f46e5',
        },
        dark: {
          ...require('daisyui/src/theming/themes')['dark'],
          primary: '#818cf8',
          'primary-focus': '#6366f1',
        },
      },
    ],
  },
};

Customization 2: Adding Multiple Pricing Tiers

ShipFast comes with one plan by default. Adding multiple tiers:

// config.ts — add multiple plans
export const config = {
  // ... other config
  stripe: {
    plans: [
      {
        name: 'Starter',
        description: 'For individuals',
        price: 9,
        priceId: process.env.STRIPE_STARTER_PRICE_ID!,
        features: ['5 projects', '1 user', 'Email support'],
        isFeatured: false,
      },
      {
        name: 'Pro',
        description: 'For small teams',
        price: 29,
        priceId: process.env.STRIPE_PRO_PRICE_ID!,
        features: ['Unlimited projects', '5 users', 'Priority support'],
        isFeatured: true,  // Highlights this plan
      },
      {
        name: 'Enterprise',
        description: 'For larger organizations',
        price: 99,
        priceId: process.env.STRIPE_ENTERPRISE_PRICE_ID!,
        features: ['Unlimited everything', 'Custom SSO', 'SLA'],
        isFeatured: false,
      },
    ],
  },
};
// app/api/stripe/create-checkout/route.ts — handle plan selection
export async function POST(req: Request) {
  const { priceId } = await req.json();
  const session = await getServerSession(authOptions);

  // Validate priceId is one of our valid plans
  const validPriceIds = config.stripe.plans.map(p => p.priceId);
  if (!validPriceIds.includes(priceId)) {
    return Response.json({ error: 'Invalid plan' }, { status: 400 });
  }

  // Create checkout session with the specified price
  const checkoutSession = await stripe.checkout.sessions.create({
    mode: 'subscription',
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${config.url}/dashboard?success=true`,
    cancel_url: `${config.url}/pricing`,
    customer_email: session!.user!.email!,
    metadata: { userId: session!.user!.id },
  });

  return Response.json({ url: checkoutSession.url });
}

Customization 3: Adding Team/Organization Support

ShipFast doesn't include multi-tenancy. Adding basic teams:

// prisma/schema.prisma — add organization models
model Organization {
  id        String   @id @default(cuid())
  name      String
  slug      String   @unique
  createdAt DateTime @default(now())
  members   OrganizationMember[]
  subscription Subscription?
}

model OrganizationMember {
  id             String       @id @default(cuid())
  organizationId String
  userId         String
  role           String       @default("member") // "owner" | "admin" | "member"
  createdAt      DateTime     @default(now())
  organization   Organization @relation(fields: [organizationId], references: [id])
  user           User         @relation(fields: [userId], references: [id])

  @@unique([organizationId, userId])
}
// lib/organization.ts
export async function createOrganization(userId: string, name: string) {
  const slug = slugify(name) + '-' + nanoid(6);

  return prisma.organization.create({
    data: {
      name,
      slug,
      members: {
        create: {
          userId,
          role: 'owner',
        },
      },
    },
  });
}

export async function getUserOrganizations(userId: string) {
  return prisma.organizationMember.findMany({
    where: { userId },
    include: { organization: true },
    orderBy: { createdAt: 'asc' },
  });
}

Customization 4: Swapping NextAuth for Clerk

If you need Clerk's prebuilt UI and organization features:

// app/layout.tsx — wrap with ClerkProvider
import { ClerkProvider } from '@clerk/nextjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

// middleware.ts — protect routes
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

const isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);

export default clerkMiddleware((auth, req) => {
  if (isProtectedRoute(req)) auth().protect();
});

// Replace session checks throughout the app
// Before (NextAuth): const session = await getServerSession(authOptions);
// After (Clerk): const { userId } = await auth();

Warning: This replacement touches most API routes. Budget 2-3 days.


Customization 5: Replacing Mailgun with Resend

ShipFast historically used Mailgun. Switching to Resend (more developer-friendly):

// lib/email.ts — replace Mailgun with Resend
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function sendWelcomeEmail(email: string, name: string) {
  return resend.emails.send({
    from: 'welcome@yoursaas.com',
    to: email,
    subject: 'Welcome to YourSaaS!',
    react: <WelcomeEmailTemplate name={name} />,
    // ^ Resend supports React Email templates natively
  });
}
// emails/WelcomeEmailTemplate.tsx — using React Email
import {
  Body, Container, Head, Heading, Html, Link, Preview, Text,
} from '@react-email/components';

export function WelcomeEmailTemplate({ name }: { name: string }) {
  return (
    <Html>
      <Head />
      <Preview>Welcome to YourSaaS</Preview>
      <Body style={{ backgroundColor: '#ffffff', fontFamily: 'sans-serif' }}>
        <Container>
          <Heading>Welcome, {name}!</Heading>
          <Text>Thanks for signing up...</Text>
          <Link href="https://yoursaas.com/dashboard">Get started →</Link>
        </Container>
      </Body>
    </Html>
  );
}

Staying Updated

After customizing, keep the upstream available:

# Add ShipFast's updates repo as a remote (if they provide one)
git remote add upstream <shipfast-updates-url>

# Check what changed in a specific file
git diff HEAD upstream/main -- lib/stripe.ts

# Apply only the security-related changes
git log upstream/main --oneline --grep="security"
git cherry-pick <commit-hash>

Most ShipFast customizations don't conflict with boilerplate updates, which are usually: dependency updates, bug fixes, and new optional features you can ignore.


Compare ShipFast with other customizable boilerplates on StarterPick.

Check out this boilerplate

View ShipFast on StarterPick →

Comments