skip to content

In a Livewire update request, in what order do boot, hydrate, booted, the update hooks, the called action, rendering, rendered and dehydrate run, and which bugs does that order explain?

level: seniorimportance: should knowfreq 30%

answer

  1. snapshot restored before boot
  2. boot, hydrate, booted
  3. all writes, then all updated hooks
  4. action after the updated hooks
  5. render, then dehydrate, then snapshot

basics

~20 s

Livewire restores public state, then runs boot(), hydrate() and hydrateFoo(), booted(), the updating hooks as values are written, all updated hooks, the called actions, rendering()/rendered() around the view, and finally dehydrate() before taking the new snapshot.

solid answer

~40 s

On an update request Livewire verifies the snapshot checksum and restores public properties, then calls `boot()`, `hydrate()`, a `hydrateFoo()` per property and `booted()`. Next it applies the incoming updates: each `updating*` hook runs as its value is written, and **all** `updated*` hooks run after every write. Then it calls the requested actions, renders with `rendering()` before and `rendered()` after the view, and ends with `dehydrate()` and `dehydrateFoo()` before the new snapshot. That order explains real bugs: an action runs after the `updated*` hooks and can overwrite their result; a value set in `rendered()` or `dehydrate()` misses this response's HTML; `booted()` is the first hook that sees the component's real state on both request types; and an `updated*` hook sees sibling fields changed in the same request.

go deeper

for a junior

Recall the broad order: restore state, boot and hydrate, apply updates, run the action, render, dehydrate.

for a middle

Explain that updated hooks run after all writes and before actions, and that render hooks bracket the view.

for a senior

Use the order to diagnose one-click-late UI, actions clobbering hook results and costly per-request queries in boot or hydrate.

for a principal

Encourage one recalculation path per derived value so hook order cannot produce inconsistent totals across a large component library.

## The pipeline, step by step A **Livewire update request** carries three things: the component's signed **snapshot**, a set of **updates** (property paths with new values) and a list of **calls** (actions to run). The server handles them in a fixed order: 1. **Restore.** Livewire checks the snapshot checksum, creates a new instance of the class and writes the public properties back onto it. 2. **`boot()`** and its trait-suffixed versions, then the trait hooks named `initialize` plus the trait name. 3. **`hydrate()`**, then one **`hydrateFoo($value)`** per public property. 4. **`booted()`**. 5. **Updates.** For each incoming path: `updating($path, $value)` and the property-level `updating*` hook, then the write. The matching `updated*` hooks are collected and run only **after every update in the request has been written**. 6. **Actions.** Each requested method runs in turn. 7. **Render.** `rendering($view, $data)`, the Blade view, then `rendered($view, $html)`. 8. **`dehydrate()`**, then one **`dehydrateFoo($value)`** per public property. 9. **Snapshot.** The new state is serialised and signed for the browser. The first render differs only at the start: `mount()` takes the place of `hydrate()` and the `hydrateFoo()` calls, and there are no updates or calls. ## Bugs the order explains | Symptom | Cause in the order | |---|---| | An action "resets" a total that the user just edited | the action runs after `updated*` and overwrites its result | | A flag set in `rendered()` does not appear on screen | the HTML is already produced; the flag lands in the snapshot | | `boot()` reads `$this->orderId` as the default on first load | on the first render `boot()` runs before `mount()` | | An `updated*` hook sees the new discount code sent alongside the quantity | all writes happen before any `updated*` hook | | Rejecting input in `updated*` is too late | the value is already written; use `updating*` | ## Using the order on an order form Say a quantity input and an **Apply coupon** button are submitted together. The quantity update is written first, `updatedItems()` recalculates the subtotal, and only then does `applyCoupon()` run, so the coupon sees the new subtotal. If instead the discount were computed in `updatedItems()` and the coupon action recomputed the subtotal from stale data, the user would see a total that disagrees with the lines. Putting the recalculation in one method that both call keeps the result consistent. ## Hooks that do not always run - **Render hooks** do not fire when rendering is skipped for the request. - **Update hooks** fire only when the request carries updates. - **`exception()`** fires only when a hook or action throws. ## Performance consequences Everything in steps 2 to 4 runs on **every** interaction, before Livewire even knows what the user did. A query in `boot()` or `hydrate()` therefore costs one round trip to the database per click or per sent keystroke. Prefer loading data lazily in the action or view that needs it, or in a cached computed value, and keep the per-request hooks to cheap restoration work. ## Clients cannot jump the queue The browser cannot call a lifecycle hook as an action: Livewire blocks method names such as `mount`, `boot`, `booted`, `hydrate*`, `dehydrate*`, `updating*`, `updated*`, `rendering`, `rendered` and `exception`, including trait-suffixed boot and mount hooks, with `DirectlyCallingLifecycleHooksNotAllowedException`. So the order above is the only order in which they run. ## How to answer in an interview A strong answer walks the pipeline once, then turns it into diagnosis: "the value was one click late because it was set in `rendered()`", "the action overwrote what `updatedItems()` computed", "the query ran on every keystroke because it lived in `hydrate()`". Interviewers at senior level are less interested in reciting nine steps than in hearing that the candidate has used the order to find a real bug, and knows which hook to move the code into to fix it.

  • Why is booted() often a safer place than boot() for code that reads component state?
    `booted()` runs after `mount()` on the first render and after `hydrate()` on later requests, so on both paths the component's real state is in place. `boot()` on the first render runs before `mount()`, when properties still hold declared defaults.
  • A property changed in rendered() shows up one click late. Why, and how do you fix it?
    `rendered()` runs after the HTML is produced, so the change only reaches the snapshot and appears on the next render. Move the logic to an `updated*` hook, the action, or `rendering()` so it runs before the view renders.
  • What happens if the browser sends a call to hydrate or updatedQuantity as an action?
    Livewire refuses it with `DirectlyCallingLifecycleHooksNotAllowedException`. Lifecycle methods, including trait-suffixed boot and mount hooks, are on a protected list, so a user cannot trigger them out of order.

saying these in an interview costs you the question

  • Says the called action runs before the property updates are applied.
  • Believes each updated hook runs immediately after its own property is written.
  • Expects a property changed in rendered() to show in the same response.
  • Thinks boot() sees mount() values on the first render.
  • Assumes the browser may call hooks such as hydrate() as actions.