LogoLaunchSaaS

Features Configuration

Centralized feature configuration and modular architecture

Features Configuration

LaunchSaaS uses a centralized feature configuration system that allows you to easily enable, disable, or switch between different service providers without modifying environment variables or code throughout your application.

Configuration File

All feature configurations are managed in src/configuration/features.ts:

import { Features } from "@/schemas/site-configuration";

export const features: Features = {
  email: {
    provider: "resend",
  },
  newsletter: {
    provider: "resend",
  },
  storage: {
    provider: "disabled",
  },
  authentication: {
    magicLink: true,
    captcha: {
      enabled: true,
      provider: "cloudflare-turnstile",
    },
    oauths: {
      google: true,
      github: true,
    },
  },
  payment: {
    provider: "stripe",
    hooks: {
      github: true,
      email: true,
    },
  },
};

Feature Modules

Email

Configure email service providers for transactional emails.

Available Providers:

  • resend - Resend email service
  • disabled - No-op provider (logs to console)

Configuration:

email: {
  provider: "resend", // or "disabled"
}

Learn more: Email Documentation

Newsletter

Configure newsletter service providers for managing subscriptions.

Available Providers:

  • resend - Resend Audiences
  • disabled - No-op provider (logs to console)

Configuration:

newsletter: {
  provider: "resend", // or "disabled"
}

Learn more: Newsletter Documentation

Storage

Configure storage providers for file uploads.

Available Providers:

  • s3 - S3-compatible storage (AWS S3, Cloudflare R2, MinIO)
  • disabled - No-op provider (logs to console)

Configuration:

storage: {
  provider: "s3", // or "disabled"
}

Learn more: Storage Documentation

Payment

Configure payment providers and post-payment hooks.

Available Providers:

  • stripe - Stripe payments
  • creem - Creem payments
  • disabled - No-op provider (logs to console)

Configuration:

payment: {
  provider: "stripe", // "stripe" | "creem" | "disabled"
  hooks: {
    github: true,  // Enable GitHub repository access
    email: true,   // Enable payment confirmation emails
  },
}

Payment Hooks

Payment hooks allow you to run custom logic after payment completion:

  • github - Automatically adds customers as GitHub collaborators
  • email - Sends payment confirmation emails

Learn more: Payment Documentation

Authentication

Configure authentication methods and providers.

Configuration:

authentication: {
  magicLink: true,  // Enable passwordless login
  captcha: {
    enabled: true,
    provider: "cloudflare-turnstile", // or "hcaptcha", "captchafox"
  },
  oauths: {
    google: true,  // Enable Google OAuth
    github: true,  // Enable GitHub OAuth
  },
}

Learn more: Authentication Documentation

Architecture Benefits

1. Centralized Configuration

All feature toggles are in one place, making it easy to see what's enabled at a glance.

2. Provider Flexibility

Switch between providers by changing a single configuration value:

// Switch from Stripe to Creem
payment: {
  provider: "creem", // Changed from "stripe"
}

3. Factory Pattern

Each module uses a factory pattern to instantiate the correct provider:

// Example: Email Provider Factory
export class EmailProviderFactory {
  static getProvider(): Provider {
    const type = features.email.provider;
    switch (type) {
      case "resend":
        return ResendProvider.create();
      case "disabled":
        return new NoOpEmailProvider();
    }
  }
}

4. No-Op Providers

When a feature is disabled, a no-op provider is used that:

  • Logs operations to console (for debugging)
  • Doesn't require environment variables
  • Allows development without external services

5. Type Safety

The Features type ensures compile-time validation:

export interface Features {
  email: {
    provider: "resend" | "disabled";
  };
  newsletter: {
    provider: "resend" | "disabled";
  };
  storage: {
    provider: "s3" | "disabled";
  };
  payment: {
    provider: "stripe" | "creem" | "disabled";
    hooks: {
      github: boolean;
      email: boolean;
    };
  };
  authentication: {
    magicLink: boolean;
    captcha: {
      enabled: boolean;
      provider: "cloudflare-turnstile" | "hcaptcha" | "captchafox";
    };
    oauths: {
      google: boolean;
      github: boolean;
    };
  };
}

Adding Custom Providers

To add a custom provider to any module:

1. Implement Provider Interface

Create a new provider class implementing the module's provider interface:

// Example: Custom email provider
export class CustomEmailProvider implements Provider {
  async sendEmail(options: SendEmailOptions): Promise<SendEmailResult> {
    // Your implementation
  }
}

2. Register in Factory

Add your provider to the factory:

// In src/lib/email/factory.ts
case "custom":
  return new CustomEmailProvider();

3. Update Type Definitions

Add your provider to the Features type:

// In src/schemas/site-configuration.ts
email: {
  provider: "resend" | "custom" | "disabled";
}

4. Configure

Enable your custom provider:

// In src/configuration/features.ts
email: {
  provider: "custom",
}

Best Practices

Development vs Production

Use different configurations for different environments:

const isDevelopment = process.env.NEXT_PUBLIC_APP_ENV === "local";

export const features: Features = {
  email: {
    provider: isDevelopment ? "disabled" : "resend",
  },
  // ... other features
};

Feature Flags

Use the configuration for feature flags:

// Check if a feature is enabled
if (features.payment.hooks.github) {
  // GitHub integration logic
}

Environment Validation

Providers validate required environment variables at startup:

export class ResendProvider implements Provider {
  constructor() {
    if (!env.RESEND_API_KEY) {
      throw new Error("RESEND_API_KEY is required");
    }
  }
}

This ensures you catch configuration errors early.

References

Next Steps