Designing a Modular Laravel Starter Kit Architecture

I've been building kit — a modular Laravel + React starter kit where you only pay for and receive the features you actually need. No dead code, no unused modules, no bloat.

The hardest part wasn't building the features. It was building the system that lets me ship a clean, customized codebase for every combination of modules a buyer selects.

The Problem with Starter Kits

Most starter kits give you everything. You buy it, clone it, and then spend the first week deleting the 60% you don't need. Billing code is tangled with team management. Notification channels are hardcoded into controllers. Removing a feature means hunting through dozens of files.

I wanted something different: you pick the modules you need at checkout, and the generated project contains only that code — as if it was built from scratch with just those features. I wrote a deep dive on the extraction engine and the CLI installer that makes this possible.

Feature Annotations

The core mechanism is a simple annotation system. Every piece of code that belongs to a specific module is tagged:

PHP

These annotations exist in controllers, models, migrations, React components, routes — everywhere. The extraction engine reads them and knows exactly what to include or remove.

Kit Module Selection

The Manifest

A features.json manifest defines the relationship between modules:

  • Which files belong to which feature
  • Dependencies between features (billing requires teams, for example)
  • Bundle definitions (SaaS Bundle, Maker Bundle, Everything)
  • What gets extracted and what stays as core

This manifest is the single source of truth. When I add a new file to a module, I update the manifest, and the extraction engine handles the rest.

The Extraction Engine

When a buyer completes their purchase, the CLI installer:

  1. Validates their license key
  2. Reads their selected modules
  3. Clones the full codebase
  4. Runs the extraction engine to strip unselected features
  5. Cleans up unused imports, routes, and dependencies
  6. Delivers a pristine project

The result is a project that looks hand-built. No leftover annotations, no conditional feature checks, no dead code paths.

Eating My Own Dog Food

The kit website itself runs on kit. The licensing system that validates buyer keys? That's the Licenses module. The blog you're reading? That's the Blog module. The billing system? That's the Billing module.

Every module I sell is actively used in production. If something breaks, I feel it first.

Current Modules

Here's what's available:

ModuleWhat It Does
BillingStripe/Paddle/LemonSqueezy subscriptions, one-time payments, credits
TeamsWorkspaces, invitations, roles (Owner/Admin/Member), per-seat billing
LicensesKey generation, activation limits, device tracking, customer portal
AdminUser management, impersonation, billing overview, content management
Notifications9 channels: email, Slack, Discord, Teams, Telegram, SMS, webhooks, in-app, WebSocket
BlogCategories, tags, SEO, scheduling, featured images
RoadmapPublic voting, user suggestions, approval workflow
ChangelogVersioned releases, RSS, scheduling
DocsMarkdown docs, search (Algolia/Meilisearch/Typesense), feedback
OnboardingMulti-step wizard, progress tracking

What's Next

I'm currently polishing the admin panel UI and fixing some edge cases in the onboarding flow. Once those are solid, I'll be launching the first public beta.

Building in public means you get to see the messy middle — and right now, it's very much the messy middle.

Related articles