skip to content

In a Livewire component, which lifecycle hooks run only on the first render, which only on later requests, and which on every request?

level: middleimportance: must knowfreq 52%

answer

  1. the object is rebuilt every request
  2. boot and booted: always
  3. hydrate: later requests only
  4. dehydrate runs before the snapshot
  5. hydrateFoo per public property

basics

~10 s

mount() runs only on the first render; hydrate() and hydrateFoo() run only on later requests; boot(), booted(), dehydrate() and dehydrateFoo() run on every request, and rendering()/rendered() whenever the view renders.

solid answer

~30 s

Livewire rebuilds the component object on **every** request, so hooks are split by request type. The first render runs `boot()`, then `mount()`, then `booted()`. A later request restores public properties from the signed snapshot, then runs `boot()`, `hydrate()`, a `hydrateFoo($value)` for each public property, and `booted()`. Both kinds then render (`rendering()`/`rendered()`) and finish with `dehydrate()` and a `dehydrateFoo($value)` per property, just before the new snapshot is taken. That is why `boot()` is the place to re-create **protected** state, which is never in the snapshot, and why `hydrate()` suits code that must only run when state came back from the browser.

go deeper

for a junior

Remember the split: mount once, hydrate only on later requests, boot and dehydrate every time.

for a middle

Explain the snapshot round trip and why protected state must be rebuilt in boot() while public state is restored automatically.

for a senior

Watch per-request cost: boot() and hydrate() run on every interaction, so queries there multiply with every keystroke a live input sends.

for a principal

Set a team rule for where derived and non-serialisable state lives, so components stay cheap to rebuild on each request.

## Why Livewire needs more than a constructor A **Livewire component** is not kept alive on the server between interactions. Each interaction is a new HTTP request that carries a **snapshot**: the component's public property values, metadata and a checksum. Livewire verifies the checksum, builds a **new** instance of the class, writes the public properties back onto it, runs the request, then serialises the state into a fresh snapshot for the browser. Turning PHP state into that JSON is **dehydration**; turning it back into a PHP object is **hydration**. Because the object is rebuilt each time, `__construct()` is not a place for setup: Livewire documents that components use `mount()` for one-time initialisation instead. Every other hook exists to let code run at a specific point of that rebuild cycle. ## The two request shapes | Hook | First render | Later request | |---|---|---| | `boot()` | yes, before `mount()` | yes, before `hydrate()` | | `mount()` | yes | no | | `hydrate()` | no | yes | | `hydrateFoo($value)` | no | yes, once per public property | | `booted()` | yes, after `mount()` | yes, after `hydrate()` | | `updating*` / `updated*` | no | only when updates arrive | | `rendering()` / `rendered()` | yes | yes, unless rendering is skipped | | `dehydrate()` | yes | yes | | `dehydrateFoo($value)` | yes, once per public property | yes, once per public property | `Foo` stands for the StudlyCase property name: a public `$lineItems` gets `hydrateLineItems($value)` and `dehydrateLineItems($value)`. ## What each hook is for - **`boot()`** runs at the start of every request. On a later request the public properties have already been restored when it runs; on the first render they still hold their declared defaults because `mount()` has not run yet. Its classic job is re-creating **protected or private properties**, which Livewire never puts in the snapshot and therefore loses between requests. - **`booted()`** runs after `mount()` or `hydrate()`, so it sees the component's real state on both request types. - **`hydrate()`** runs only when a component came back from the browser. Use it for work that makes no sense on the first render, such as turning a plain array from the snapshot back into a richer object. - **`dehydrate()`** runs at the end of every request, after rendering and just before the snapshot is taken, so it can convert state back into something Livewire can serialise. - **`hydrateFoo()` / `dehydrateFoo()`** do the same for one property and receive its value. ## A worked example on an order form An order form keeps its lines in `public array $lines` and a protected `TaxCalculator` service. The calculator is not serialisable and is not public, so it vanishes after the first request. Setting it in `boot()` restores it every time; setting it in `mount()` would work once and then leave a `null` on the next click. ## Common mistakes 1. Initialising protected state in `mount()` and being surprised it is gone on the next request. 2. Expecting `hydrate()` on the first render; it only runs when a snapshot is restored. 3. Changing a property in `dehydrate()` and expecting the HTML to show it: the view has already rendered, although the change is written into the snapshot. 4. Doing heavy queries in `boot()` or `hydrate()`, which multiplies their cost by every interaction. Livewire's own documentation recommends **Wireables or Synthesizers** over hand-written `hydrate()`/`dehydrate()` pairs for custom types, and a computed property over a `boot()`-loaded value for most derived data. ## Choosing the right hook When deciding where a piece of setup code belongs, ask two questions: does it need to run on every request, and does it need the restored state? | Need | Hook | |---|---| | once, with parameters from the page | `mount()` | | every request, state not needed | `boot()` | | every request, state needed | `booted()` | | only when coming back from the browser | `hydrate()` | | convert state before it is serialised | `dehydrate()` | This table is also a good way to answer the interview question aloud: name the split, then give one concrete job for each hook, such as rebuilding a protected service in `boot()` or converting a value object back to an array in `dehydrate()`.

  • On a later request, do public properties already hold the browser's values when boot() runs?
    Yes. Livewire verifies the snapshot and writes the public properties onto the new instance before it calls `boot()`. Incoming updates from that request have not been applied yet; they are written after `booted()`. On the first render `boot()` sees only declared defaults, because `mount()` has not run.
  • Why does a protected property set in mount() become null on the next click?
    Only public properties go into the snapshot. The next request builds a fresh object, restores the public ones, and never calls `mount()` again, so the protected property is back to its default. Assign it in `boot()`, or derive it on demand.
  • If dehydrate() changes a public property, where does that change show up?
    In the snapshot sent back to the browser, not in the HTML of the current response: `dehydrate()` runs after the view has rendered and before the snapshot is taken. The change becomes visible in the markup on the next render.

A Livewire component is like a hotel room turned over for each stay: the guest's suitcase (public properties) travels with them, but the minibar (protected properties) has to be restocked by housekeeping (boot) every single check-in.

saying these in an interview costs you the question

  • Believes Livewire keeps the component object alive in server memory between requests.
  • Puts one-time setup in __construct() of a Livewire component.
  • Thinks hydrate() runs on the first render as well.
  • Expects protected properties to survive between requests like public ones.
  • Claims dehydrate() runs only on later requests.