How to Build a SaaS Boilerplate with Auth & Subscriptions in 30 Minutes Using Wave

42 views 0 likes 0 comments 20 minutesOriginalTutorial

A practical guide to setting up a fully functional SaaS application using the Wave Laravel starter kit. Learn how to configure the environment, add a custom dashboard, and integrate Stripe for test payments in under 30 minutes.

#Laravel #SaaS #PHP #Stripe #Tailwind #Indie Development #Starter Kit
How to Build a SaaS Boilerplate with Auth & Subscriptions in 30 Minutes Using Wave

How to Build a SaaS Boilerplate with Auth & Subscriptions in 30 Minutes Using Wave

Introduction: Have You Ever Faced This?

Last week, a friend of mine who's an indie developer mentioned that he spent over a month writing his core business logic, only to realize that "infrastructure" features like user authentication, subscription billing, and admin dashboards took up nearly half his time. To make matters worse, his payment integration kept failing intermittently due to Stripe webhook issues.

This scenario is incredibly common. The hardest part of building a SaaS isn't writing the core features—it's building all the modules that every SaaS needs from scratch.

Today, I'll show you how to use Wave—a Laravel-based SaaS Starter Kit—to spin up a fully functional SaaS skeleton in under 30 minutes. It comes pre-packaged with user authentication, subscription billing, role management, a blog system, and an admin panel. Features that would normally take two weeks to build. After this guide, you'll save massive amounts of time and focus entirely on your core product.


Prerequisites

Before we begin, ensure your environment meets the following requirements:

  • PHP >= 8.1 (Wave runs on Laravel 10+, which requires PHP 8.1+)
  • Composer (PHP package manager)
  • MySQL or SQLite (SQLite is highly recommended for rapid local prototyping)
  • Node.js & NPM (For compiling frontend assets, as Wave uses Tailwind CSS)
  • Basic Laravel knowledge (Familiarity with Artisan commands, routing, and Blade templates is sufficient)

Pro Tip for macOS users: Consider installing Laravel Herd. It sets up PHP, Nginx, and your database with one click. You can even spin up Wave instantly using herd new --starter-kit=devdojo/wave.


Quick Start: Getting Wave Running Step-by-Step

Step 1: Create the Project

Open your terminal and run:

bash 复制代码
composer create-project devdojo/wave my-saas-app
cd my-saas-app

This pulls down all of Wave's dependencies, including the Laravel framework itself and Wave's SaaS modules. Once Composer finishes, you'll see a standard Laravel directory structure, but with additional wave/ configuration and view files.

Why use Composer? Wave is fundamentally a Laravel starter kit. Installing via Composer guarantees consistent dependency versions and prevents the merge conflicts that often happen when manually cloning a repository.

Step 2: Configure Environment Variables

bash 复制代码
cp .env.example .env
php artisan key:generate

Open the .env file and configure your database connection. For local development, I highly recommend SQLite for zero-config simplicity:

env 复制代码
DB_CONNECTION=sqlite
## Comment out or remove other DB_ prefixed lines

Then, create the SQLite database file:

bash 复制代码
touch database/database.sqlite

Step 3: Run Migrations & Seed Data

bash 复制代码
php artisan migrate --seed

This command creates all necessary database tables (users, subscription plans, roles, permissions, etc.) and populates them with initial data, such as default subscription tiers (Free, Pro). Wave handles the base schema for you, so you don't need to write custom migrations just to get started.

Step 4: Start the Development Server

bash 复制代码
php artisan serve

Visit http://localhost:8000 in your browser, and you should see Wave's default landing page. Click the Register button in the top-right corner to test the sign-up flow.

At this point, you have a running SaaS application with registration and login capabilities. Total time elapsed: less than 5 minutes.


Practical Examples: Adding Custom Pages & Setting Up Stripe Test Mode

Getting it running is just the beginning. Let's dive into two hands-on exercises: creating a custom business dashboard and switching the payment environment to Stripe's test mode.

Exercise 1: Creating Your SaaS Dashboard Page

Let's say you're building an "AI Writing Assistant" SaaS and need a user dashboard after login. Create a controller and route:

bash 复制代码
php artisan make:controller DashboardController

Edit app/Http/Controllers/DashboardController.php:

php 复制代码
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class DashboardController extends Controller
{
    public function index()
    {
        // Wave's auth middleware handles redirects automatically if the user isn't logged in
        $user = auth()->user();
        $plan = $user->plan()->first();
        
        return view('wave::dashboard', [
            'user' => $user,
            'plan' => $plan,
            'usage' => $this->getUsage($user),
        ]);
    }

    private function getUsage($user)
    {
        // Return your business-specific metrics here, e.g., API call counts
        return [
            'words_generated' => 1250,
            'api_calls' => 48,
        ];
    }
}

Add the route in routes/web.php:

php 复制代码
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', [App\Http\Controllers\DashboardController::class, 'index'])
         ->name('dashboard');
});

Create the view file at resources/views/vendor/wave/dashboard.blade.php, leveraging Wave's Blade component layout:

blade 复制代码
@extends('wave::app')

@section('content')
<div class="max-w-4xl mx-auto py-8">
    <h1 class="text-2xl font-bold mb-4">Welcome back, {{ $user->name }}!</h1>
    <div class="bg-white rounded-lg shadow p-6">
        <p>Current Plan: {{ $plan->name ?? 'Free' }}</p>
        <div class="mt-4 grid grid-cols-2 gap-4">
            <div class="p-4 bg-gray-50 rounded">
                <p class="text-sm text-gray-500">Words Generated</p>
                <p class="text-xl font-bold">{{ number_format($usage['words_generated']) }}</p>
            </div>
            <div class="p-4 bg-gray-50 rounded">
                <p class="text-sm text-gray-500">API Calls</p>
                <p class="text-xl font-bold">{{ $usage['api_calls'] }}</p>
            </div>
        </div>
    </div>
</div>
@endsection

Why use the wave:: namespace? Wave's views are registered under the wave:: prefix. By publishing vendor views, you can copy the default templates into resources/views/vendor/wave/ and customize them safely. This ensures your overrides aren't overwritten during future Wave upgrades.

Exercise 2: Configuring Stripe Test Payments

Wave natively supports Stripe and Paddle. Always use test mode during development:

  1. Create a Stripe account and navigate to Dashboard → Developers → API Keys.
  2. Copy the Publishable key and Secret key (Test keys start with pk_test_ and sk_test_).
  3. Update your .env file:
env 复制代码
STRIPE_KEY=pk_test_xxxxxxxxxxxxxxxx
STRIPE_SECRET=sk_test_xxxxxxxxxxxxxxxx
BILLING_PROVIDER=stripe

Wave's billing module automatically reads these variables. Creating subscription plans is straightforward. You can add them via the Wave admin panel (/admin → Billing → Plans) or via Tinker:

php 复制代码
php artisan tinker

>>> \Wave\Plan::create([
...     'name' => 'Pro',
...     'price' => 19.99,
...     'interval' => 'month',
...     'features' => json_encode(['Unlimited Writing', 'API Access', 'Priority Support']),
... ]);

Refresh the homepage and click Pricing to see your Pro plan. Clicking Subscribe will redirect you to the Stripe Checkout test page. Use Stripe's test card number 4242 4242 4242 4242 to complete the payment flow.


Troubleshooting & Common Pitfalls

  1. Missing Frontend Styles? Run npm install && npm run dev to compile Tailwind and Vite. If styles still look broken, verify that vite.config.js correctly points the entry to resources/css/app.css.
  2. Stripe Webhooks Not Receiving Locally? Use the Stripe CLI for local forwarding during development: stripe listen --forward-to localhost:8000/webhook/stripe. In production, configure the real webhook URL and verify signature security.
  3. Views Overwritten After Upgrading Wave? If you customized Blade templates, make sure you copied them from vendor/devdojo/wave/resources/views to resources/views/vendor/wave/ before editing. Never modify files directly in the vendor/ directory, as composer update will wipe them out.
  4. SQLite Foreign Key Errors During Migration? Add DB_FOREIGN_KEYS=true to your .env file, and ensure your config/database.php SQLite configuration includes 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true).

Summary & Next Steps

In just a few minutes, we installed and launched Wave, built a custom user dashboard, and integrated Stripe test payments. You now hold a fully functional SaaS skeleton capable of user registration, authentication, and paid subscriptions.

Recommended Next Steps:

  • Integrate your core business logic (e.g., OpenAI API calls, document processing)
  • Explore Wave's plugin system to extend functionality cleanly, rather than modifying core files
  • Set up a mail queue to asynchronously send subscription success/failure notifications
  • Migrate from SQLite to a production-grade MySQL/PostgreSQL database and deploy to a VPS or PaaS

Wave saves you from reinventing the wheel, but it doesn't replace your business logic. For indie developers, the time saved on boilerplate is the exact time you should spend polishing your product.

Have questions? Drop them in the comments below, and I'll reply to each one.

Last Updated:2026-07-31 10:05:52

Comments (0)

Post Comment

Loading...
0/500
Loading comments...