Getting started
How Nitro works
Each Nitro component runs in two places. This page explains what the compiler makes of your code, what the server sends on the first load, and what happens when you click and when you call the server.
On this page
The compiler
Nitro reads each component's class and view and compiles them to JavaScript. It compiles the methods the
browser can reach, and turns the view into a tree of elements with its dynamic parts. During development,
this happens on the first request after you change a component. For production, you run
php artisan nitro:build to do it ahead of time.
- PHP's rules still hold. Arrays are values,
==compares the way PHP compares, strings are bytes, and functions behave as PHP's do. All of this is checked against PHP itself. - The browser only gets what it needs. Nitro never compiles a method the browser can't reach, such as a helper that you only call from
mount(). - Mistakes fail the build. A browser method that queries the database, or a view the browser can't render the same way, causes an error that names the file and line. You find out during development, not in production.
The first render
The server renders the page with Blade, just as Laravel renders any view. The HTML arrives complete, so it appears quickly and search engines and link previews can read it. Along with it comes each component's state, signed by the server.
The browser then takes over the page. It doesn't render the page again. Instead, it attaches to the elements the server sent, so nothing moves or flickers. From then on, the component is live.
What happens on a click
nitro:click="increment" calls the compiled increment() method in the browser.
The method changes $count, and only the parts of the view that read $count
render again. This works because, when the view was compiled, every dynamic part recorded which properties
it reads:
<div>
<button nitro:click="increment">+</button>
<p>Clicked {{ $count }} times</p> {{-- reads $count --}}
<p>Hello, {{ $name }}</p> {{-- reads $name, so a click leaves it alone --}}
@foreach ($authors as $author) {{-- reads $authors, so neither one changes it --}}
<li>{{ $author }}</li>
@endforeach
</div>
| A change runs | Then compares | |
|---|---|---|
| Livewire | the whole view, on the server | the new HTML against the page |
| React, Vue | the component’s render function | the new virtual DOM against the last one |
| Nitro | the expressions that read the property | nothing: each one updates its own node |
What happens on a server call
A method marked #[Server] runs on the server. Each call is a single request:
-
The browser sends the signed state
It sends the component's state exactly as the server signed it, the properties it has changed since, and the method with its arguments.
-
The server checks everything
- The state is one the server signed, for this session and this user, and it hasn't been changed.
- The page's middleware (
auth,can, ...) still lets the visitor in. - Every changed property is public, isn't
#[Locked], has its declared type, and passes its#[Validate]rules. - The method is a
#[Server]method, and each argument has its parameter's type.
-
The method runs
It runs like any other Laravel code, with queries, mail, the session and the container. Models are always read again from the database, never taken from the browser.
-
The browser renders what changed
The response holds the new signed state, along with any events, redirects or messages. Only the parts of the view that read a changed property render again.
The browser can send anything
Anyone can call your endpoint without using the page. An unlocked property can arrive with any value of its type. So check whatever a #[Server] method relies on, with #[Validate] rules or $this->validate().
Navigation
A link with nitro:navigate changes the page without a full reload. Laravel routes the visit
as usual, with its middleware, bindings and redirects, and the browser shows the new page in place of the
old one. The first visit to any URL always gets the server's complete HTML. These docs work this way.
In production
nitro:build compiles every component, minifies it with esbuild, and publishes versioned files
to public/nitro. The web server sends these files without PHP, and browsers cache them for a
year. Each page is in a file of its own, which loads the first time someone visits it. The files hold
views and browser methods, never data. The state travels with each response.