flyo/nitro-laravel
Seamlessly connect your Laravel application to Flyo Nitro. This package provides configuration, service bindings, and convenient helpers for fetching and rendering Nitro content, so you can build fast, content-driven sites with familiar Laravel tooling.
Install the module through Composer and publish its configuration:
composer require flyo/nitro-laravel
php artisan vendor:publish --tag=nitro-config
Set the credentials the module reads at boot — typically a project/space token plus an optional API base URL and cache TTL:
NITRO_TOKEN=your-project-token
NITRO_API_URL=https://nitro.flyo.cloud
NITRO_CACHE_TTL=300
Look here first:
config/nitro.php — token, endpoint, cache store, and any enabled features. This is the file you will touch most.NitroServiceProvider — it shows what is bound into the container (the API client, the facade alias, any middleware).vendor/flyo/nitro-laravel/src) rather than trusting blog posts.First use case — render a CMS page through a catch-all route. The module's core value is letting Flyo own the page tree while Laravel owns routing and rendering:
// routes/web.php
Route::get('/{slug?}', PageController::class)
->where('slug', '.*')
->name('nitro.page');
// app/Http/Controllers/PageController.php
public function __invoke(Request $request, string $slug = '/')
{
$page = Nitro::page($slug, locale: app()->getLocale());
abort_if($page === null, 404);
return view('page', ['page' => $page]);
}
That gives you a working site in one route. Everything below builds on it.
Catch-all controller, not catch-all middleware. A single invokable controller keeps the fetch, the 404 policy, and the view selection in one obvious place. Reserve middleware for cross-cutting concerns (locale resolution, redirects, injection of navigation data) so the controller stays testable.
Render blocks, don't echo HTML. Nitro returns structured blocks. Map each block type to a Blade component and loop over them — this is the pattern that scales:
@foreach ($page->blocks as $block)
<x-dynamic-component :component="'nitro.'.$block->type" :block="$block" />
@endforeach
Keep a default/fallback component for unknown types so a new block type in the CMS doesn't break the site on deploy day.
Cache at the fetch boundary, keyed by everything that varies. The client call is the slow, failure-prone part. Cache the hydrated object, and make the key explicit about locale, draft state, and slug:
$key = "nitro:page:{$locale}:{$slug}:".($draft ? 'draft' : 'live');
return Cache::remember($key, config('nitro.cache_ttl'), fn () => Nitro::page($slug, $locale, $draft));
If you use taggable stores, tag by content type so you can flush navigation and pages independently when editors publish.
Resolve navigation once per request. Navs are requested on nearly every page. Fetch them in a view composer or a scoped singleton binding, and cache them with the same TTL strategy — never fetch the menu inside a Blade loop.
Draft/preview mode via signed URLs. Expose preview through a signed route so only editors with a valid Flyo-generated link bypass the cache:
Route::get('/preview/{slug}', PreviewController::class)
->middleware('signed')
->where('slug', '.*');
Pass draft: true to the client, skip the cache, add X-Robots-Tag: noindex, and never let the draft flag leak into shared cache keys.
Localization as an explicit argument. Resolve the locale from route prefix, Accept-Language, or a session preference — but pass it down explicitly. Avoid reading app()->getLocale() deep inside the client, or you'll get cache collisions when the locale changes mid-request (queues, console commands, tests).
Fail soft on API outages. Wrap fetches in a try/catch on the transport exception, then serve a cached copy if available, or a friendly 503/placeholder. A CMS API hiccup should not take down a marketing site's homepage.
Fake the client in tests. Bind a stub implementation of the client contract into the container and return fixture payloads. This keeps tests fast and, more importantly, makes the package's payload shape part of your own test suite — valuable when the upstream package is low-traffic and changes rarely get documented.
@json block. Treat preview tokens as scoped, short-lived credentials; if a preview link leaks, rotate./admin, /api, health checks, and asset routes before the {slug} route. On Apache/Nginx, also confirm the web server doesn't serve stale static files ahead of Laravel.$block->type ?? 'unknown', null-safe property access). A missing CMS field should degrade gracefully, not throw a 500 on every page.{!! !!}. Trusting CMS HTML is fine until an editor pastes something from a compromised source."flyo/nitro-laravel": "^1.0" with a tested lockfile), read CHANGELOG.md before upgrading, and skim the diff — the surface is small enough to review in minutes.config/nitro.php) in local, log the raw response body on transport errors in staging, and use php artisan tinker to call the client directly and inspect the payload shape before writing view code.nitro. namespace. Because the service provider is registered by package discovery, you can also dont-discover it and register manually if you need to control binding order relative to your own providers.How can I help you explore Laravel packages today?