lacodix/laravel-plans
Manage SaaS plans and addons with subscriptions, billing intervals, and countable or unlimited features like credits and tokens that auto-reset. Consume feature usage across plans in order, with translations, sorting, and metadata. No billing included.
Architecture fit
HasSubscriptions on any Eloquent model, polymorphic relation) means the same primitives serve User, Team, or Tenant. If the roadmap includes seat-based or workspace-based subscription models, we do not pay a second integration cost later. If we are single-user SaaS only, that generality is free but unused.main plan and one or more addon plans, and usage drains feature allocations in subscription order until buckets are exhausted. Hand-rolling this is where most in-house entitlement systems accumulate subtle bugs — partial consumption, reset boundaries, "unlimited" sentinels. Buying this is the strongest argument for adoption.laravel-translatable for plan/feature names, eloquent-sortable for display and consumption ordering). No exotic dependencies, no proprietary runtime, no queue worker assumptions.Integration feasibility
composer require, auto-discovered provider, published migrations, one trait on one model. No credentials, no external service, no webhook endpoint, no outbound network calls. A single engineer can stand up a working sandbox in under a day.composer require as the milestone is off by an order of magnitude.SubscriptionRenewed, plus subscription-created and plan-change events) is the integration contract with our invoice provider. That means billing coupling is an event listener, not a fork of the package — good for both upgrade safety and for swapping providers later.price column plus effectiveMeta() / effectivePrice() and isInTrial() give us enough to display pricing and proration, and meta gives us a place to stash currency or provider price IDs. It does not compute money correctly for tax or currency conversion. Treat every monetary field as presentation and routing data, with the provider as the source of truth.Technical risk
effectiveMeta, isInTrial, effective price, force renew) — a good signal that the maintainer is active and responsive. But there is no foundation, no second maintainer, no commercial support contract, no LTS commitment. Continuity planning is mandatory, not optional.plans, features, subscriptions, and pivot tables. Laravel Cashier ships its own subscriptions table. Running both in one database requires renaming one side or isolating schemas. This is a real, concrete integration defect that surfaces in migrations and in every query that touches subscriptions. It must be resolved in design, not discovered in staging.~1.5 and reading the changelog on every bump is required hygiene, not paranoia.Key questions to resolve before committing
subscriptions table collision if Cashier is present or planned?Stack fit
laravel-plans holds entitlement state → application code asks "does this subscriber have feature X, how much remains, consume N."Migration path
subscriptions name collision up front by configuring table prefixes; (b) seed the plan/feature catalog to mirror current production plans, keeping slugs as the stable application-facing identifiers; (c) wire event listeners that generate no invoices yet, only log, so we validate the renewal event fires where we expect; (d) build a read-only comparison job that evaluates both old and new entitlement checks for real traffic and reports divergence; (e) flip consumers of entitlement checks feature by feature.slug, never by ID. The README states slugs are the app-facing identity; honoring that gives us a cheap rebuild path if the catalog has to be reseeded from a different source.meta, and treat the price column as display-only unless we have deliberately decided otherwise.Compatibility
laravel-translatable is a soft coupling: if we already use it, plan and feature naming is a non-issue; if we do not, either adopt it or store single-locale names. Determine this before the catalog seed, because it affects the shape of production data.Sequencing
Maintenance
Support
Scaling
Failure modes
subscriptions table. Mitigation: resolve at design time and assert the table name in a test.Ramp-up
How can I help you explore Laravel packages today?