Skip to main content

ShipFlutter Review 2026: Flutter SaaS Boilerplate

·StarterPick Team
Share:

TL;DR

ShipFlutter is a well-structured Flutter SaaS boilerplate that takes Flutter's write-once-run-everywhere premise seriously. Auth, Stripe (via backend), Supabase, push notifications, and a marketing landing page in one package. At ~$149, it's priced reasonably for the cross-platform coverage. Best for teams who specifically need Flutter (mobile + web + desktop from one codebase).

What You Get

Price: ~$149 (check shipflutter.dev for current pricing)

Core features:

  • Flutter 3.x + Dart
  • Auth: Supabase Auth (email + OAuth)
  • Database: Supabase (PostgreSQL via RLS)
  • Payments: Stripe via backend API
  • Push notifications: Firebase Cloud Messaging
  • State management: Riverpod
  • Navigation: GoRouter
  • UI: Custom + Material Design 3
  • Web landing page (Flutter web)
  • Dark/light mode

The Cross-Platform Case

Flutter's primary advantage: one codebase targets iOS, Android, Web, macOS, Windows, Linux.

// main.dart — same entry point for all platforms
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Supabase.initialize(
    url: const String.fromEnvironment('SUPABASE_URL'),
    anonKey: const String.fromEnvironment('SUPABASE_ANON_KEY'),
  );

  runApp(
    const ProviderScope(
      child: ShipFlutterApp(),
    ),
  );
}

Supabase Authentication

// lib/features/auth/auth_repository.dart
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final supabase = Supabase.instance.client;

class AuthRepository {
  Future<void> signInWithEmail(String email, String password) async {
    await supabase.auth.signInWithPassword(
      email: email,
      password: password,
    );
  }

  Future<void> signInWithGoogle() async {
    await supabase.auth.signInWithOAuth(
      OAuthProvider.google,
      redirectTo: 'your-app://callback',
    );
  }

  Future<void> signOut() async => supabase.auth.signOut();

  Stream<AuthState> get authStateChanges =>
      supabase.auth.onAuthStateChange;

  User? get currentUser => supabase.auth.currentUser;
}

// Provider for auth state
final authStateProvider = StreamProvider<AuthState>((ref) {
  return ref.read(authRepositoryProvider).authStateChanges;
});

State Management with Riverpod

// lib/features/subscription/subscription_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

// Async subscription state
final subscriptionProvider = FutureProvider<Subscription?>((ref) async {
  final user = ref.watch(currentUserProvider);
  if (user == null) return null;

  final response = await supabase
      .from('subscriptions')
      .select()
      .eq('user_id', user.id)
      .maybeSingle();

  return response != null ? Subscription.fromJson(response) : null;
});

// Usage in widgets
class PricingWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final subscription = ref.watch(subscriptionProvider);

    return subscription.when(
      data: (sub) => sub?.isActive == true
          ? const PremiumContent()
          : const UpgradePrompt(),
      loading: () => const CircularProgressIndicator(),
      error: (e, _) => Text('Error: $e'),
    );
  }
}

Stripe Integration

Flutter doesn't run Stripe directly — it calls a backend:

// Stripe checkout via backend API
class BillingRepository {
  final Dio _dio = Dio();

  Future<String> createCheckoutSession(String priceId) async {
    final user = supabase.auth.currentUser!;
    final token = supabase.auth.currentSession!.accessToken;

    final response = await _dio.post(
      '${AppConfig.apiUrl}/create-checkout-session',
      data: {'priceId': priceId, 'userId': user.id},
      options: Options(headers: {'Authorization': 'Bearer $token'}),
    );

    return response.data['url'] as String;
  }
}

// Open Stripe checkout in browser
Future<void> openCheckout(String url) async {
  if (await canLaunchUrl(Uri.parse(url))) {
    await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
  }
}

ShipFlutter includes a Node.js/Express backend for Stripe handling.


Flutter vs React Native for SaaS

FactorFlutterReact Native
PerformanceNear-native (renders own pixels)JS bridge overhead
Web supportExcellentLimited (React Native Web)
Desktop supportNative macOS/Windows/LinuxElectron (separate)
EcosystemDart pub.devnpm (JS)
Team skillsRequires DartJavaScript/React
StripeVia backendreact-native-stripe SDK
UI consistencyPixel-perfect across platformsPlatform-native
Job marketSmallerLarger

Choose Flutter when:

  • You need desktop apps (macOS/Windows) in addition to mobile/web
  • UI pixel-perfect consistency across platforms matters
  • Team is willing to learn Dart

Choose React Native when:

  • Team is JavaScript-first
  • Platform-native UI feel is important
  • Access to React web component knowledge

Limitations

  • Dart requirement — Smaller talent pool than JavaScript
  • Web performance — Flutter web is still not quite as fast as native web
  • Stripe in browser — Mobile payments require backend calls + deep linking
  • App store compliance — IAP (In-App Purchase) required for subscription payments on iOS/Android (not Stripe)

The IAP limitation is important: Apple and Google require in-app purchases for subscription products on mobile. ShipFlutter handles this via a separate IAP implementation, but it adds complexity.


Who Should Buy ShipFlutter

Good fit:

  • Founders who specifically want iOS + Android + Web from one codebase
  • Products needing desktop apps (macOS/Windows)
  • Teams with Flutter/Dart experience
  • B2B SaaS where mobile is an add-on to web (not the primary)

Bad fit:

  • Consumer mobile apps where App Store IAP is the primary billing (Stripe can't be the payment method)
  • Teams who want JavaScript ecosystem access
  • Products where web performance is paramount

Final Verdict

Rating: 3.5/5

ShipFlutter is a solid boilerplate for teams committed to Flutter. The cross-platform coverage is genuinely impressive — shipping iOS, Android, and web from one codebase is a real advantage. The IAP complexity for App Store subscription billing and smaller Dart ecosystem are real constraints. For Flutter teams, it's the best starting point available.



Getting Started with ShipFlutter

# After purchase — clone and install Flutter dependencies
git clone https://your-shipflutter-repo.git my-flutter-app
cd my-flutter-app

# Install Flutter 3.x if not already installed
flutter doctor

# Copy and configure environment
cp .env.example .env
# Configure:
# SUPABASE_URL=https://your-project.supabase.co
# SUPABASE_ANON_KEY=eyJ...
# STRIPE_PUBLISHABLE_KEY=pk_test_...
# BACKEND_URL=https://your-backend.railway.app

flutter pub get
flutter run  # Runs on connected device or simulator

The backend (Node.js/Express) deploys separately for Stripe handling. Connect it to Railway or Render as a persistent service. The Flutter app connects to both Supabase (auth + database) and your backend (billing). Expect 30-45 minutes for initial setup including Supabase project creation, Stripe configuration, and first device run.


App Store Billing: The IAP Requirement

The most important caveat for mobile subscription products: Apple and Google require in-app purchases (IAP) for subscription billing on iOS and Android. ShipFlutter ships with both Stripe (for web) and an IAP implementation (for mobile).

// lib/features/billing/iap_service.dart
import 'package:in_app_purchase/in_app_purchase.dart';

class IAPService {
  final InAppPurchase _iap = InAppPurchase.instance;

  Future<void> buySubscription(String productId) async {
    const productIds = {'monthly_pro', 'annual_pro'};
    final response = await _iap.queryProductDetails(productIds);
    
    final product = response.productDetails
        .firstWhere((p) => p.id == productId);
    
    final purchaseParam = PurchaseParam(productDetails: product);
    await _iap.buyNonConsumable(purchaseParam: purchaseParam);
  }
}

This means you're managing two payment systems: Stripe for web users and IAP for mobile. Apple takes 15-30% of IAP revenue (vs Stripe's 2.9%). For web-primary SaaS where mobile is a companion app, Stripe handles most transactions and the IAP complexity is manageable. For mobile-first consumer apps where most subscriptions happen in-app, the revenue split is a significant cost consideration.


ShipFlutter vs React Native Boilerplates

For teams evaluating Flutter vs React Native for a SaaS product:

FactorShipFlutter (Flutter)React Native Starter
PlatformsiOS + Android + Web + DesktopiOS + Android (web is limited)
UI consistencyPixel-perfect (Flutter renders)Platform-native feel
JavaScript❌ Dart✅ TypeScript/React
Desktop apps✅ Native❌ (Electron needed)
Supabase✅ Official Dart SDK✅ JS SDK
Stripe mobileVia IAP + backendreact-native-stripe-sdk
Talent poolSmallerLarger

React Native's larger talent pool and JavaScript ecosystem are real advantages for teams hiring or using existing JS knowledge. Flutter wins for teams that need desktop apps, want pixel-perfect UI consistency across all platforms, or have existing Dart expertise.


Key Takeaways

  • ShipFlutter provides cross-platform Flutter foundation: iOS, Android, Web, and Desktop from one Dart codebase
  • Supabase handles auth and database; a separate Node.js backend handles Stripe webhooks
  • App Store billing requires in-app purchases for mobile subscription revenue — plan for Apple and Google's 15-30% revenue share
  • Best for teams committed to Flutter who need mobile + web parity, particularly for B2B products where web is primary and mobile is a companion experience
  • React Native is the better choice if your team is JavaScript-first or if you need platform-native UI feel
  • At $149, ShipFlutter is priced fairly for the cross-platform coverage it provides — comparable to React Native boilerplates at the same price point but targeting a different developer profile
  • Flutter web continues to improve each release; for B2B dashboards where pixel-perfect consistency matters more than raw web performance, it's increasingly viable in 2026
  • The Riverpod state management included in ShipFlutter is one of Flutter's most robust patterns — teams adopting the template get a well-structured state architecture, not just auth and billing scaffolding
  • GoRouter navigation (also included) is the current Flutter community standard for handling deep links and auth-protected routes across iOS, Android, and web platforms

Deployment Architecture for Flutter SaaS

A Flutter SaaS app involves more deployment targets than a Next.js or React Native app: the Flutter web app, a separate backend for billing, the Supabase project (managed), mobile app releases to App Store and Google Play, and optionally a desktop distribution.

For the web app, Flutter web deployments to Vercel or Netlify are straightforward — the flutter build web output is a static site with a service worker. Deploy the /build/web directory directly. The Flutter web app communicates with the Supabase project for data and your billing backend for payment flows.

The billing backend (Node.js/Express in ShipFlutter's case) deploys to Railway or Render as a persistent server. This backend receives Stripe webhooks, creates checkout sessions, and updates subscription status in Supabase. It's a small service — typically 200-400 lines of Node.js — but it's a required deployment target.

Mobile builds follow standard Flutter release workflows: flutter build apk for Android and flutter build ipa for iOS. ShipFlutter's configuration handles app signing and environment-specific builds. The App Store and Google Play submission process is the same as any Flutter app — nothing in ShipFlutter simplifies or complicates the store review process.

Desktop builds (macOS, Windows, Linux) are the unique advantage. flutter build macos produces a native macOS app that uses the same codebase as the web and mobile versions. For B2B SaaS where desktop access matters — admin tools, data-heavy workflows, tools used by power users — the Flutter desktop output is compelling. React Native requires Electron for desktop, which adds significant bundle size and memory overhead; Flutter's desktop output is native and lightweight.

The Flutter SaaS Market Reality

Flutter SaaS boilerplates represent a niche within an already-niche market. Most SaaS founders choose Next.js because the ecosystem, tutorials, hiring, and community are orders of magnitude larger. The Flutter choice is driven by specific requirements: needing desktop apps alongside mobile, wanting pixel-perfect UI consistency, or having existing Dart expertise that would be wasted on a JavaScript stack.

The founders who get the most value from ShipFlutter are typically building tools where the product itself is a multi-platform app. Internal company tools, professional tools for creative workflows, and mobile companion apps for web SaaS are the natural fits. Consumer subscription apps where App Store billing is the primary monetization channel are a worse fit, given the IAP requirement and 15-30% revenue share.

For teams evaluating whether Flutter is the right foundation, the clearest signal is whether desktop support is a near-term requirement. If the answer is yes, Flutter's native desktop output justifies the smaller ecosystem and Dart learning curve. If the answer is no, Next.js or React Native are safer choices with better community support.


See our guide to best Flutter boilerplates 2026 for the full comparison including FlutterFlow alternatives.

Browse best mobile SaaS starters for the React Native perspective on cross-platform SaaS.

Compare cross-platform options in our best SaaS boilerplates overview.

Check out this boilerplate

View ShipFlutteron StarterPick →

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.