Search by

lauroguedes / laravel-demo-mode

lauroguedes

Turn a Laravel installation into a public playground: seeded data, scheduled resets, rotating credentials, and a belt of restrictions that keeps a stranger from abusing the server.

v1.6.0 2026-09-26 11:28 UTC

This package is auto-updated.

Last update: 2026-09-26 11:30:34 UTC


README

Tests Latest Version Packagist Downloads License

Turn a Laravel installation into a public playground: seeded data, a scheduled reset, rotating credentials published on the login page, and a belt of restrictions that keeps a stranger from abusing the server.

Publishing a starter kit, a boilerplate or a SaaS with a browsable demo needs the same five pieces every time — a flag, a rebuild on a cycle, credentials a stranger can use that do not become a permanent fact of the internet, a list of things the demo must not do, and a visible notice that the data is temporary. This is those five pieces, extracted from two demos that have been running in public.

This package drops tables. Read docs/security.md before you install it anywhere. A wrong configuration erases your database.

Laravel Demo Mode pill bar on bottom centralized

Installation

composer require lauroguedes/laravel-demo-mode
php artisan demo:install

demo:install is additive: it publishes the config, appends the DEMO_ keys to .env.example, and offers to write a DemoSeeder stub. It does not touch .env and it does not turn the demo on — that is an act you perform on the deployment you meant.

It asks two questions, because neither answer can be inferred from the project: whether every visitor sees the same data or each gets their own corner of it, and whether to start a DemoSeeder or point the reset at a seeder you already have. Answer shared if you are not sure. --sandbox=shared|scoped and --without-seeder answer both for a script, and a run with nobody at the keyboard takes shared and writes the seeder.

Making an installation a demo

DEMO_MODE=true
DEMO_RESET_SCHEDULE="0 */6 * * *"
// config/demo.php
'environments'  => ['demo'],
'allowed_hosts' => ['demo.example.com'],

Write the demonstration data into database/seeders/DemoSeeder.php, then check your work:

php artisan demo:doctor

It exits non-zero on anything that would destroy data or publish a secret, so it belongs in your deploy pipeline ahead of the first reset.

Using it

use LauroGuedes\DemoMode\Facades\Demo;

Demo::enabled();        // the single point of truth
Demo::nextResetAt();    // derived from the cron, so a countdown cannot lie
Demo::credentials();    // what the login form should prefill
Demo::toArray();        // one payload for Blade, Livewire and Inertia
{{-- Both render nothing when this is not a demo, so no wrapper is needed --}}
<x-demo-banner />   {{-- a floating bar the package styles itself --}}
<x-demo-credentials />

@notdemo
    <a href="{{ route('oauth.google') }}">Sign in with Google</a>
@endnotdemo

For Inertia, return Demo::toArray() from your own HandleInertiaRequests::share(). For Blade and Livewire, the optional ShareDemoState middleware puts the same payload in every view. See docs/frontend.md.

Letting visitors reset it

'on_demand' => ['enabled' => true],

Off by default — it puts a migrate:fresh behind an HTTP request. Throttled, cooled down, queued, CSRF-protected and host-checked; see docs/on-demand-reset.md.

Isolating visitors from each other

'sandbox' => ['driver' => 'scoped'],

Each visitor gets the seeded baseline plus what they created. Not multi-tenancy and not a security boundary; see docs/sandbox.md.

Commands

Command What it does
demo:install Publish the config, and a seeder stub if you want one
demo:reset Rebuild the demonstration data. --dry-run prints the plan
demo:status What this installation currently is
demo:doctor Audit the configuration. Non-zero exit on anything dangerous
demo:credentials Show, or --rotate, the published passwords
demo:snapshot Capture the baseline the snapshot strategy restores
demo:sandbox:prune Remove the sandboxes nobody came back to

Working with an AI agent

If the project uses Laravel Boost, this package ships its own guidelines and an agent skill. php artisan boost:install picks them up with no configuration.

The guidelines are the short, always-loaded part: that this package drops tables, that Demo::enabled() is the single source of truth, that the view components already decide for themselves whether to render, and that a seeder must read the published password from Demo::passwordFor() rather than hardcoding one — which is the mistake that fails silently after the first rotation.

The demo-mode-development skill carries the rest, loaded only when it is relevant: reset strategies, per-visitor isolation, cleaners, restrictions, write guards and the on-demand reset.

What it is not

  • Password-protecting a work in progress. That is php artisan down --secret.
  • Backup and restore. That is spatie/laravel-backup.
  • A demo data generator. The seeder is yours; the package runs it.
  • Multi-tenancy. Visitor isolation is deliberately ephemeral and disposable.

Documentation

Full documentation is in docs/. Start with security.md — it is the one that is not optional.

Already have a hand-rolled demo mode? UPGRADE.md is mostly a list of things to delete.

Testing

composer test

Credits

Extracted from lauroguedes/laravel-sso and lauroguedes/mary-ui-starter-kit, which had each solved this badly in their own way first.

License

The MIT License. See LICENSE.md.

If this is useful to you, please star the repository.
It is the thing that helps other people find it.

⭐ Star this project  ·  ☕ Buy me a coffee

Crafted by an Artisan ♥ Lauro Guedes