next-supabase-stripe-starter

repository·main·Indexed 21 days ago

https://github.com/kolbysisk/next-supabase-stripe-starter

A production-ready SaaS starter kit built with Next.js 15, Supabase (Auth/DB), Stripe (Payments/Subscriptions), and Resend (Email). It features a fully integrated workflow for managing users, subscriptions, and product data via webhooks and fixtures, utilizing a feature-based colocation pattern for project organization.

Tokens
6.4K
Snippets
21
Records
27
Agent score
73%

What's inside next-supabase-stripe-starter

  1. Manage Products via stripe-fixtures.json

    main

    Products and prices are managed via stripe-fixtures.json. When you update this file and run the fixture command, the webhook at src/app/api/webhooks automatically synchronizes the changes to your Supabase database.

    Adding Custom Metadata

    You can store custom information in the metadata field of a product in the fixture. To use this data in a type-safe way:

    1. Add your field (e.g., team_invites) to the fixture metadata.
    2. Update the Zod schema in src/features/pricing/models/product-metadata.ts.
    3. Parse the metadata in your application code.
    const products = await getProducts();
    const productMetadata = productMetadataSchema.parse(products[0].metadata); // Now it's typesafe 🙌!
    productMetadata.teamInvites; // The value you set in the fixture
  2. Project File Structure and Organization

    main

    The project follows a feature-based colocation pattern:

    • Features: Code related to a specific business logic unit is grouped in src/features/[feature-name]. This includes models, components, and logic specific to that feature.
    • UI Components:
      • Reusable, feature-agnostic components live in src/components.
      • shadcn/ui generated components live in src/components/ui.
    • App Router: General UI and routing logic lives in the src/app directory.
    • API Routes: Webhooks and other endpoints are located in src/app/api.
  3. Quickstart: Deploy and Setup the Starter

    main

    To bootstrap your SaaS, follow these high-level steps:

    1. Setup Supabase: Create a project and reset the database password to ensure it contains no special characters (to avoid CLI issues).
    2. Setup Stripe: Create a project and enable the Customer Portal active test link.
    3. Setup Resend: Create an account, generate an API Key, and add the Supabase Resend integration.
    4. Deploy to Vercel: Use the deployment button or clone the repo. You must provide environment variables including NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_DB_PASSWORD, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and RESEND_API_KEY.
    5. Configure Stripe Webhook: Add an endpoint in the Stripe Dashboard pointing to YOUR_VERCEL_URL/api/webhooks. Select all events and copy the signing secret to your Vercel STRIPE_WEBHOOK_SECRET environment variable.
    6. Initialize Database: Run Supabase migrations to create tables.
    7. Bootstrap Products: Use Stripe fixtures to populate products.
    8. Finalize: Replace all UPDATE_THIS placeholders in the codebase (except in .env.local.example) with your actual credentials.
  4. Configure Stripe Webhooks

    main

    To synchronize Stripe data with your Supabase database, you must configure a webhook endpoint:

    1. Find your Vercel deployment URL.
    2. In the Stripe Dashboard, navigate to Developers -> Webhooks.
    3. Add an endpoint with the URL: {YOUR_VERCEL_URL}/api/webhooks.
    4. Select all events.
    5. Copy the signing secret revealed in the dashboard.
    6. Add this secret to your Vercel project settings as the STRIPE_WEBHOOK_SECRET environment variable.
  5. Run Supabase Migrations

    main

    Use the Supabase CLI to initialize and link your project to create the necessary database schema.

    1. Login: bunx supabase login
    2. Initialize: bunx supabase init
    3. Update package.json: Replace UPDATE_THIS_WITH_YOUR_SUPABASE_PROJECT_ID with your actual Supabase project ID.
    4. Link project: bun run supabase:link
    5. Apply migrations: bun run migration:up
    bunx supabase login
    bunx supabase init
    bun run supabase:link
    bun run migration:up
  6. Manage Database Schema with Migrations

    main

    All database schema changes must be performed through migrations. To add a new table (e.g., invites):

    1. Create a new migration file: npm run migration:new add-invites-table
    2. Edit the generated SQL file to include your schema:
      create table invites (
        id uuid not null primary key default gen_random_uuid(),
        email text not null
      );
      alter table invites enable row level security;
    3. Apply the migration: npm run migration:up
    npm run migration:new add-invites-table
    npm run migration:up
  7. Bootstrap Products with Stripe Fixtures

    main

    Instead of manually creating products in the Stripe UI, use the stripe-fixtures.json file to define your product offering and run the fixture command.

    1. Install the Stripe CLI (e.g., brew install stripe/stripe-cli/stripe on Mac).
    2. Run the fixture command using your Stripe Secret Key (SK):
    stripe fixtures ./stripe-fixtures.json --api-key YOUR_STRIPE_SK
    stripe fixtures ./stripe-fixtures.json --api-key UPDATE_THIS_WITH_YOUR_STRIPE_SK
  8. How the 'sexy' variant works with SexyBoarder

    main

    When the Button component is used with the variant="sexy" prop, it automatically wraps its content in a SexyBoarder component via the WithSexyBorder helper. Other variants render as standard buttons without this extra wrapper. This allows for a specialized visual effect specifically for the 'sexy' style without complicating the logic for standard buttons.

    // This will render with the SexyBoarder wrapper
    <Button variant="sexy">Special Effect</Button>
    
    // This will render as a standard button
    <Button variant="default">Normal Button</Button>
  9. Configure the Stripe Webhook endpoint

    main

    The application uses a POST endpoint at /api/webhooks to synchronize Stripe data (products, prices, and subscriptions) with Supabase. To ensure successful synchronization, you must configure your Stripe Webhook settings to point to this URL and provide the correct signing secret.

    Required Environment Variable

    You must set the following environment variable in your deployment environment:

    • STRIPE_WEBHOOK_SECRET: The signing secret provided by the Stripe Dashboard when you create a webhook endpoint.

    Supported Stripe Events

    The webhook handler specifically listens for and processes the following events:

    • product.created / product.updated: Synchronizes product details.
    • price.created / price.updated: Synchronizes pricing information.
    • customer.subscription.created / customer.subscription.updated / customer.subscription.deleted: Synchronizes user subscription status.
    • checkout.session.completed: Triggers subscription creation when a user completes a subscription-mode checkout session.
    STRIPE_WEBHOOK_SECRET=whsec_...
  10. Send Emails with Resend and React Email

    main

    Emails are located in src/features/emails. To send an email using the built-in resendClient:

    import WelcomeEmail from '@/features/emails/welcome';
    import { resendClient } from '@/libs/resend/resend-client';
    
    resendClient.emails.send({
      from: 'no-reply@your-domain.com',
      to: userEmail,
      subject: 'Welcome!',
      react: <WelcomeEmail />,
    });
  11. Configure Prettier settings

    main

    The project uses Prettier for code formatting with the prettier-plugin-tailwindcss plugin enabled to handle Tailwind CSS class sorting. The following formatting rules are applied:

    • Quotes: Uses single quotes (singleQuote: true) and single quotes for JSX attributes (jsxSingleQuote: true).
    • Semicolons: Required (semi: true).
    • Indentation: 2 spaces (tabWidth: 2).
    • Spacing: Brackets have spacing (bracketSpacing: true).
    • JSX Brackets: Brackets are placed on a new line (jsxBracketSameLine: false).
    • Arrow Functions: Always include parentheses around parameters (arrowParens: 'always').
    • Line Length: Maximum line width is 120 characters (printWidth: 120).
    ```javascript
    /** @type {import(
  12. Configure Next.js middleware matcher for Supabase session management

    main

    The middleware uses a specific regex matcher to ensure Supabase session updates run on all request paths except for static assets, optimized images, and common icon files. This prevents unnecessary server-side execution for files that do not require session validation.

    If you need to exclude additional file extensions or paths, modify the matcher array in src/middleware.ts.

    export const config = {
      matcher: [
        '/((?!_next/static|_next/image|favicon.ico|.*\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
      ],
    };