Nitro

Going further

Modules and packages

A module of your app, or a package you publish, can keep its components, pages and stores in folders of its own. It registers them under a namespace, and its components are named with it: billing::invoice-table.

On this page

By default Nitro finds components in app/Nitro/Components, pages in app/Nitro/Pages and stores in app/Nitro/Stores. That suits most apps. A large app split into modules, each owning its screens, or a package that ships components, needs its own folders instead. That's what nitro.namespaces is for. It works like Blade's view namespaces: Laravel's loadViewsFrom(..., 'billing') gives you billing::invoice views, and a Nitro namespace gives you billing::invoice-table components.

Registering a namespace

The module's service provider adds its namespace in register(), and loads its Blade views in boot(), as any Laravel package does:

PHP
// modules/Billing/BillingServiceProvider.php
namespace Billing;

use Illuminate\Support\ServiceProvider;

class BillingServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        config()->set('nitro.namespaces.billing', [
            'components' => [
                'namespace' => 'Billing\Ui\Components',
                'path' => __DIR__.'/Ui/Components',
                'views' => 'billing::components',
            ],
            'pages' => [
                'namespace' => 'Billing\Ui\Pages',
                'path' => __DIR__.'/Ui/Pages',
                'views' => 'billing::pages',
            ],
            'stores' => [
                'namespace' => 'Billing\Ui\Stores',
                'path' => __DIR__.'/Ui/Stores',
            ],
        ]);
    }

    public function boot(): void
    {
        $this->loadViewsFrom(__DIR__.'/resources/views', 'billing');
    }
}

Each part is optional: a module with components only leaves out pages and stores. Each takes what nitro.components, nitro.pages and nitro.stores take: the classes' PHP namespace, their folder, and for components and pages the prefix of their Blade views.

  • The name. A namespace is named in kebab case, such as billing or billing-admin. pages and stores are taken: they start page and store names.
  • Views. A component's view is its name under views: billing::components.invoice-table, from the Blade namespace the provider loads. Without views, it is billing::invoice-table.
  • Folders inside folders. Pages may sit inside the components' folder, as Ui/Components/Pages would. A class belongs to the most specific folder that holds it, so those are pages, not components.

Names

A class in the namespace is named as the app's are, with the namespace in front:

Class Name
Billing\Ui\Components\InvoiceTable billing::invoice-table
Billing\Ui\Components\Reports\Summary billing::reports.summary
Billing\Ui\Pages\Invoices\Index pages::billing::invoices.index
Billing\Ui\Stores\Basket stores::billing::basket

A component is an ordinary Nitro component:

PHP Browser + server
// modules/Billing/Ui/Components/InvoiceTable.php
namespace Billing\Ui\Components;

use Billing\Contracts\Invoices;
use Nitro\Attributes\Server;
use Nitro\Component;

class InvoiceTable extends Component
{
    public array $invoices = [];

    public function mount(Invoices $invoices): void
    {
        $this->invoices = $invoices->open();
    }

    #[Server]
    public function markPaid(int $id, Invoices $invoices): void
    {
        $invoices->markPaid($id);
        $this->invoices = $invoices->open();
    }
}

Place it by its name, from any view: the app's, or another module's:

Blade
{{-- any view of the app, or of another module --}}
<nitro:billing::invoice-table />

{{-- a component in a folder of the module: Ui/Components/Reports/Summary.php --}}
<nitro:billing::reports.summary :year="2026" />

Pages are routed by their class, so their names rarely show. A namespace's page is a chunk of its own, as the app's are, named billing.invoices.index:

PHP
// modules/Billing/routes/web.php
use Billing\Ui\Pages\Invoices;

Route::nitro('/invoices', Invoices\Index::class);
Route::nitro('/invoices/{invoice}', Invoices\Show::class);

A store is used through a property of its type, as any store is, so its name doesn't show at all. See Sharing state.

Making components

make:nitro writes into a namespace when the name has one: the class into its folder, the view into the Blade namespace its provider loads.

Terminal
php artisan make:nitro billing::InvoiceTable
php artisan make:nitro billing::Invoices/Index --page
php artisan make:nitro billing::Basket --store

It stops with a message when the namespace isn't registered, when it has no folder for that kind (a page in a namespace without pages), or when its Blade views aren't loaded.

Vue, React, Solid and Svelte views

A namespace can have JavaScript views too. Give it a folder for each engine it uses:

PHP
// in register(), beside 'components' and 'pages'
'views' => [
    'vue' => __DIR__.'/resources/views/vue',
],

Its components name their views with the namespace:

PHP
// modules/Billing/Ui/Components/InvoiceChart.php
#[View(vue: 'billing::invoice-chart')]
class InvoiceChart extends Component
{
    // ...
}

Nitro finds invoice-chart.vue in the module's folder. Your Vite builds it, so the browser has to find it too: give the adapter the module's views with namespaced(), beside the app's. Every adapter has it: nitro/vue, nitro/react, nitro/solid and nitro/svelte.

JavaScript
// resources/js/app.js
import { nitroVue, namespaced } from 'nitro/vue';

nitroVue({
    ...import.meta.glob('../views/vue/**/*.vue'),
    ...namespaced('billing', import.meta.glob('../../modules/Billing/resources/views/vue/**/*.vue')),
});

A view named billing::invoice-chart is looked for among billing's views only, and one without a namespace among the app's only, so two modules can each have an index.vue. A view holding its own PHP, in a <php> block, works in a namespace's folder as in the app's, and is named in the namespace: billing::invoice-chart.

In a package

A package registers its namespace the same way, in its own service provider, and ships its components, pages and views in its own folders. Name the namespace after the package, so it doesn't meet another's. An app that installs it places <nitro:billing::invoice-table /> without copying anything into its own folders.

Builds and the cache

php artisan nitro:build includes every namespace's components, and its cached list is found again when a file is added to any namespace's folder, as with the app's own.