laravel/spark
Laravel Spark is a commercial SaaS scaffolding package for Laravel that provides subscription billing via Stripe or Paddle, team management, invoices, authentication, and admin tooling to help you launch recurring-revenue apps faster.
Laravel Spark is a commercial, closed-source SaaS starter kit for subscription billing, teams, invoices, and billing settings. It is not a conventional open-source Composer package: the GitHub repository is primarily informational, and installation requires a purchased license and private Composer credentials. The last release date shown is 2018, so treat Spark as a legacy system and verify PHP/Laravel compatibility before committing to it.
Minimal setup path:
composer.json / auth.json, then require the matching laravel/spark version.composer require laravel/spark
php artisan spark:install
.env, run migrations, and register at /register.app/Providers/SparkServiceProvider.php.Look first at:
config/spark.php for currency, billable model, and package configuration.app/Providers/SparkServiceProvider.php for plans, trials, teams, and add-ons.resources/views/vendor/spark and the frontend asset pipeline.php artisan route:list to see the actual endpoints rather than assuming them.First practical use case: gate a paid feature behind a subscription. Register a user, subscribe them to a defined plan, then check subscription state in controllers, middleware, policies, or Blade views.
Define plans centrally. Plans usually live in SparkServiceProvider and must use the exact plan/price identifiers from your billing provider:
Spark::useStripe()->noCardUpFront()->trialDays(14);
Spark::freePlan()
->name('Free')
->features(['Basic access']);
Spark::plan('Pro Monthly', 'price_xxx')
->price(29)
->features(['Pro access', 'Priority support']);
Spark::plan('Pro Yearly', 'price_yyy')
->price(290)
->yearly()
->features(['Pro access', 'Priority support']);
After changing this provider, clear cached configuration and routes:
php artisan config:clear
php artisan route:clear
Use the Billable trait for subscription checks. Spark’s billable model exposes common subscription operations. The exact method surface depends on the Spark version, but day-to-day checks typically look like:
if ($user->subscribed('default')) {
// active subscription
}
if ($user->onPlan('price_xxx')) {
// specific plan
}
if ($user->onTrial()) {
// trial period
}
Common billing operations:
$user->subscription('default')->swap('price_yyy');
$user->subscription('default')->cancel();
$user->subscription('default')->resume();
$invoices = $user->invoices();
return $user->downloadInvoice($invoiceId);
Wrap these calls in your own service or policy layer so future migration away from Spark is easier.
Model team billing deliberately. If teams are enabled, the billable entity is usually the team, not the individual user. Add team configuration in the provider, then check subscription state against the current team:
Spark::team()->name('Team')->trialDays(14);
$team = $user->currentTeam;
if ($team->subscribed('default')) {
// team has active billing
}
Be consistent: decide early whether users, teams, or both can own subscriptions. Mixing $user->subscribed() and $team->subscribed() without a clear rule is a common source of authorization bugs.
Gate features with explicit entitlement logic. Spark plans can declare feature labels for display, but production authorization should be explicit. Use subscription/plan checks, policies, middleware, or your own entitlement table. Avoid scattering raw plan ID checks throughout views; centralize them:
class CanUseProFeature
{
public function handle($request, Closure $next)
{
abort_unless(
$request->user()->currentTeam->onPlan('price_xxx'),
403
);
return $next($request);
}
}
Customize by publishing, not editing vendor files. Publish Spark views, assets, language files, and configuration, then override in application-level code. Keep custom Vue components and views outside the vendor path. If you need behavior changes, prefer events/listeners, route overrides, or calling Spark model methods from your own controllers rather than modifying package internals.
Handle billing webhooks outside the request path. Spark expects your billing provider’s webhook endpoint to keep local subscription state in sync. Register the correct endpoint in Stripe/Braintree, use the provider’s CLI or tunneling tool locally, and verify webhook logs when state looks stale. For side effects such as welcome emails, provisioning, or analytics, listen to Spark subscription events or your provider’s webhooks and dispatch queued jobs.
Use billing tests as regression tests. At minimum, test:
composer require laravel/spark from public Packagist. Composer authentication must be configured, and package availability depends on the vendor continuing to serve the repository. Mirror or archive the package internally if you must maintain a legacy installation.composer.json constraints against your Laravel and PHP versions before estimating work. Upgrading Laravel often requires abandoning or heavily patching Spark.STRIPE_KEY, STRIPE_SECRET, webhook secrets, and APP_URL together.$user->subscribed() can produce misleading results. Resolve the billable entity first, then check subscription state on that entity. Enforce team membership before allowing billing changes./settings, /billing, or similar paths, inspect php artisan route:list and resolve conflicts explicitly. Route caching can hide stale route assumptions; clear caches after provider changes.noCardUpFront() permits registration without a payment method, but you still need a clear flow for converting trials to paid subscriptions. Test what happens when a trial ends without a card and how your UI communicates that state.storage/logs/laravel.log, and the Stripe/Braintree dashboard webhook/event logs. Most “Spark is broken” issues are webhook, key-mode, or plan-ID mismatches.How can I help you explore Laravel packages today?