Choose your install path
Layup is a Filament form field first; the bundled Pages resource is a turnkey example built on top of it. Pick the path that fits how you plan to use it.
Path A -- Use Layup as a field on your own model. Skip the Pages resource. You bring the model, the JSON column, and your own Filament resource. Layup gives you the editor canvas. Continue at Field-only installation, then read Embedding the field.
Path B -- Use the bundled Pages resource. A full page CMS with nested pages, scheduled publishing, SEO meta, and frontend routes -- ready to use after php artisan layup:install. Continue below.
Either way, the field looks like this:
use Crumbls\Layup\Forms\Components\LayupBuilder;
LayupBuilder::make('content')->columnSpanFull()
Requirements
- PHP 8.3+
- Laravel 12+
- Filament 5
- Livewire 4
Prerequisites
Layup requires a working Filament installation. If you have not set up Filament yet:
composer require filament/filament
php artisan filament:install --panels
See the Filament installation docs for details.
Install via Composer
composer require crumbls/layup
Register the plugin
Add LayupPlugin to your Filament panel provider (e.g., app/Providers/Filament/AdminPanelProvider.php):
use Crumbls\Layup\LayupPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
LayupPlugin::make(),
]);
}
Registering the plugin makes the LayupBuilder field available in any Filament form and (unless disabled in config) registers the Pages resource in your sidebar.
Quick install (recommended)
Run the install command to handle everything in one step:
php artisan layup:install
This:
- Publishes the config file
- Runs database migrations (creates
layup_pagesandlayup_page_revisions) - Creates a storage symlink (
storage:link) so uploaded images are web-accessible - Creates the frontend layout component if it does not exist
- Publishes Filament assets (CSS)
- Generates the Tailwind safelist
- Checks your setup and warns about any issues
After running install, skip to Tailwind safelist setup.
Manual installation
If you prefer to run each step yourself:
php artisan vendor:publish --tag=layup-config
php artisan migrate
php artisan storage:link
php artisan filament:assets
php artisan layup:safelist
This creates two tables: layup_pages (configurable name) and layup_page_revisions.
Tailwind safelist setup
Layup dynamically generates CSS classes for column widths, spacing, and user-defined styles. Tailwind needs to know about these classes.
Tailwind v4
Add to your CSS entry point:
@source "../../storage/layup-safelist.txt";
Tailwind v3
Add to your tailwind.config.js:
module.exports = {
content: [
// ...
'./storage/layup-safelist.txt',
],
};
Generate the safelist file (if you did not use layup:install):
php artisan layup:safelist
When safelist.auto_sync is enabled in config (the default), the safelist regenerates automatically every time a page is saved.
Build pipeline integration
Add the safelist command to your build script so it always runs before Tailwind compiles:
{
"scripts": {
"build": "php artisan layup:safelist && vite build"
}
}
Rebuild frontend assets
npm run build
Without the safelist and rebuild steps, the page builder will work in the admin panel but frontend pages will have broken or missing styling.
Publish assets (optional)
| Tag | Command | Description |
|---|---|---|
layup-config |
php artisan vendor:publish --tag=layup-config |
Config file |
layup-views |
php artisan vendor:publish --tag=layup-views |
Blade templates |
layup-routes |
php artisan vendor:publish --tag=layup-routes |
Route file |
layup-scripts |
php artisan vendor:publish --tag=layup-scripts |
Alpine.js components |
layup-templates |
php artisan vendor:publish --tag=layup-templates |
Page templates |
layup-translations |
php artisan vendor:publish --tag=layup-translations |
Language files |
layup-stubs |
php artisan vendor:publish --tag=layup-stubs |
Widget scaffold stubs |
Verify installation
Run the health check command to confirm everything is set up correctly:
php artisan layup:doctor
Then visit /admin/pages (or your panel path) and create a new page. You should see the visual builder with rows, columns, and the widget picker.
Troubleshooting
php artisan layup:doctor runs a battery of checks and prints passed / warning / failure counts. Below are the failures you are most likely to hit and how to fix each.
"LayupPlugin is not registered in any Filament panel"
The LayupPlugin::make() call is missing from your panel provider. Add it under ->plugins([...]) (see Register the plugin). After editing, clear the config cache: php artisan config:clear.
"Table 'layup_pages' does not exist"
Migrations have not run. Run:
php artisan migrate
If you are intentionally on the field-only path and do not want these tables, see Field-only installation -- the doctor warning is expected there.
"Storage symlink missing"
Uploaded images will not be web-accessible. Run:
php artisan storage:link
"Layout component [app] not found"
Layup expects a Blade component matching frontend.layout (default: app) to exist at resources/views/components/app.blade.php. Either:
- Run
php artisan layup:install-- it copies a starter layout component if one is missing, or - Create the component manually, or
- Set
frontend.layoutinconfig/layup.phpto point to your existing layout component (e.g.,'layouts.app'forresources/views/components/layouts/app.blade.php).
"Layout does not include @layupScripts"
Interactive widgets (accordion, tabs, countdown, modals, slider, etc.) will not function without this directive. Add it to your frontend layout, typically just before the closing </body> tag:
@layupScripts
</body>
"Safelist file does not exist" / Frontend pages render without styling
Tailwind cannot see Layup's dynamically-generated classes. Verify three things in order:
- The safelist file exists -- run
php artisan layup:safelistto generate it. - Your Tailwind config or CSS entry point references the safelist path (see Tailwind safelist setup).
- You ran
npm run build(or your equivalent) after adding the safelist reference.
"Upload disk 'public' is not configured"
Your config/filesystems.php does not have a disk matching uploads.disk. Either configure the disk or set uploads.disk in config/layup.php to a disk you do have configured.
If a check is not listed here, run php artisan layup:doctor and read the message inline -- each failure includes a one-line fix hint.
Upgrades
See CHANGELOG.md for release notes, breaking changes, and version-by-version migration guidance.
Contributors
Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.