doublethreedigital/runway
Runway lets you use Eloquent models as first-class resources in Statamic, giving editors a familiar control panel for creating, editing, and listing database records without building custom addons. It bridges Laravel models with Statamic’s content workflow.
Runway (formerly "Statamic Eloquent Driver") turns existing Eloquent models into first-class Statamic content — editable in the Control Panel, queryable in Antlers/Blade, and exposed through GraphQL/REST, all while the data stays in your own tables. It's the package you reach for when content lives in a relational schema (products, events, staff, listings) rather than flat Markdown files.
Minimal setup:
composer require statamic-rad-pack/runwayphp artisan vendor:publish --tag="runway-config" → config/runway.phpresources:// config/runway.php
'resources' => [
App\Models\Post::class => [
'name' => 'Posts',
'handle' => 'post',
'blueprint' => 'post',
'title_field' => 'title',
],
],
resources/blueprints/runway/post.yaml (same YAML syntax you already know from collections; fields map onto Eloquent columns/accessors).php artisan cache:clear / statamic:stache:clear) and check the CP — "Posts" now appears as an editable content area.First use case: rendering a list on the front end without writing a controller:
{{ runway:post limit="5" sort="-published_at" }}
<h2><a href="{{ url }}">{{ title }}</a></h2>
{{ intro }}
{{ /runway:post }}
Where to look first: config/runway.php for resource definitions, resources/blueprints/runway/ for the editable field schema, and the package docs for the runway tag parameter list. If something renders blank, check the blueprint handle vs. the config handle first — the two must line up.
Resource-per-model, blueprint-per-resource. Treat each Runway resource as a mirror of one Eloquent model. Define title_field (or title_format) so listings, relationship pickers, and breadcrumbs have a human label. Augmentation works like collections: accessors/casts on the model are respected, and you can control which fields appear in the CP independently of the database schema.
Antlers tag as your query layer. {{ runway:post }} supports the query parameters you'd expect from Statamic's collection tag (limit, sort, paginate, where-style filters). Reach for it for straightforward listings; drop to Blade/the facade when you need joins, withCount, or complex scopes:
use StatamicRadPack\Runway\Runway;
$posts = Runway::model(Post::class)
->with('author')
->where('status', 'published')
->orderByDesc('published_at')
->paginate(15);
Routing and detail pages. Give a resource a route in config and Runway registers the URI, resolving the model and rendering the configured template/layout — useful for quick detail pages. For custom logic, bind the model yourself (Route::get('/posts/{post}', ...)) and let route–model binding do the work; Runway's resource handle still drives CP URLs and static cache entries.
Orderable resources (new in 9.7.0). Resources can now be drag-and-drop reordered in the CP. Add an integer sort column to the table and declare it in the resource config, then order by it in your queries (orderBy('sort')). Existing rows need an initial value — backfill the column (e.g. by id) in a migration or seeder before turning ordering on, or the CP list will look scrambled.
Relationships both ways. Runway fields can reference other Runway resources or Statamic entries, so a Product can belong to a Brand model and also surface a related entry. Define the relationship on the Eloquent model as usual and expose it via a belongs_to/has_many field in the blueprint; eager-load with with in config/runway.php or in your query to avoid N+1.
Static caching interplay (new in 9.7.0). Statamic's static cache warmer automatically includes Runway URIs; on large tables that can make a warm request expensive or time out. The new config flag lets you opt out of warming Runway URIs so you can warm them manually or via a queue instead. Set it if your warm endpoint is hitting time limits or you have tens of thousands of routable records.
API surface. Enable the API/GraphQL options in config to expose resources read-only to your front end or a separate SPA. This is often the reason to choose Runway over a collection — the data is already queryable via Eloquent, and the API is a thin layer on top.
Nested JSON titles (fixed in 9.7.0). title_field and title_format now resolve nested JSON paths (e.g. meta->title or a dotted path into a JSON column). Previously these rendered blank in listings and relationship dropdowns; if you'd worked around it with a model accessor, you can now point the config directly at the nested key.
config/runway.php or blueprints, clear Statamic's Stache and the app cache. Most "my new field isn't showing" reports are stale blueprint/resource caches.title_field must exist and be non-null. A missing or empty title field produces blank rows in the CP and unusable relationship pickers. Use title_format for composed labels, and remember nested JSON paths are now supported (9.7.0).order_by in config can make the CP list and front-end disagree — pick one source of truth.route in config competes with your own routes/web.php entries. Register one or the other; use php artisan route:list to confirm which wins.with in the resource config for relationships used in listings, or you'll silently N+1 on every Antlers loop.RefreshDatabase and factories as normal — Runway is just Eloquent underneath. Test the Antlers tag output and the CP listing (orderable drag-and-drop included) rather than only the facade.vendor:publish diffing against any published config so you pick up the new keys.How can I help you explore Laravel packages today?