Skip to content
Brok UI

Loading…

No results

Updating

Components live in your project, so an update is never a package bump that happens to you. The CLI knows three versions of every file — the pristine upstream you installed, your local copy, and the new upstream — and merges them. Files you never touched update in place. Files you edited get a three-way merge, and anything it cannot merge is staged for you to decide. Nothing is overwritten silently.

Note

The merge base for every installed file is stored, compressed, in the committed ui-lock.json; .jml/cache is only a fast local copy. That is why a fresh clone, CI, or a second machine can tell your edits from upstream changes without any extra setup — commit the lock file, ignore the cache.

The update loop

See what changed upstream

ui:status lists every installed item with its state (current, update available, upstream changed) and checks that the registry is reachable. ui:update --check goes one step further and classifies each update. Neither writes a file.

terminal
php artisan ui:status
php artisan ui:update --check
output
Updates available:

  button ........................... 1.6.0 -> 1.8.1 (safe)
  dialog ........................... 2.1.0 -> 2.2.0 (local changes detected)
  card ............................. 1.4.2 is already current.
  data-table ....................... 3.0.0 -> 4.0.0 (breaking)
  WARN  data-table has breaking changes: selection now emits row ids, not indexes.
  WARN  Skipping data-table; breaking updates require `--major`.
Classification Meaning
safe Upstream changed; you never edited the file. Applied in place.
local changes detected Upstream changed and so did you. Three-way merge.
local changes You edited it; upstream has nothing new. Left alone.
breaking The item declares a breaking change. Skipped unless you pass --major.
DOWNGRADE The registry is behind your project. Skipped unless you pass --allow-downgrade.

Read the diff before you merge

ui:diff prints two unified diffs per file: base → your local file (your edits) and base → new upstream (what you are about to merge). Read the second one; that is the change you accept.

terminal
php artisan ui:diff dialog
output
dialog 2.1.0 -> 2.2.0 (local changes detected)

resources/views/components/ui/dialog.blade.php
--- base (2.1.0)
+++ local
@@ -12,7 +12,7 @@
-    'size' => 'md',
+    'size' => 'lg',

--- base (2.1.0)
+++ upstream (2.2.0)
@@ -40,6 +40,9 @@
+    // Return focus to the trigger after close.
+    x-on:close="$refs.trigger?.focus()"

Apply the update

Name an item to update just that one, or run without arguments to update everything in the lock file. --dry-run prints the full plan without writing; --interactive confirms each item; --yes accepts the whole plan for CI. Every changed file is labelled: updated (replaced, you never edited it), merged (three-way merge applied), or unchanged locally.

terminal
php artisan ui:update --dry-run
php artisan ui:update button dialog
php artisan ui:update --yes
output
2 item(s) will change

  button ........................... 1.6.0 -> 1.8.1
  dialog ........................... 2.1.0 -> 2.2.0

  resources/views/components/ui/button.blade.php ................. updated
  resources/js/ui/button.js ...................................... updated
  resources/views/components/ui/dialog.blade.php ................. merged
  resources/js/ui/index.js ............................. updated imports

The write is transactional per run: if any file cannot be written the run rolls back and reports, so a half-applied update never lands in your tree.

Resolve a conflict

When your edit and the upstream change touch the same lines, the merge stops for that item. Your file is untouched; the incoming file and a .patch are staged under .jml/updates/<item>.

output
  ERROR  dialog: merge conflict in resources/views/components/ui/dialog.blade.php.
  WARN   Conflicts staged under [.jml/updates/dialog]. Resolve them with `php artisan ui:resolve dialog`.

ui:resolve finishes it: keep yours, take theirs, or open both in $EDITOR. A resolution records the incoming version as the next merge base and clears the staging directory.

terminal
php artisan ui:resolve --list
php artisan ui:resolve dialog --edit
php artisan ui:resolve dialog --theirs
php artisan ui:resolve dialog --ours
output
Pending conflicts (1)

  dialog ........................... resources/views/components/ui/dialog.blade.php

Pin what must not move

A pinned item is skipped by bulk updates until you unpin it or pass --force. Pin at install time with ui:add --pin or afterwards:

terminal
php artisan ui:pin data-table
php artisan ui:pin --list
php artisan ui:pin data-table --unpin

Update the foundation

resources/css/ui.css and _styles.php are shared by every component and versioned separately as the foundation. Items declare the minimum foundation they need, and ui:update refuses an install that would outrun it. ui:foundation three-way merges those two files the same way, with --ours / --theirs for overlapping hunks.

terminal
php artisan ui:foundation --check
php artisan ui:foundation --dry-run
php artisan ui:foundation --yes

Breaking, unstable, and declarative migrations

  • Breaking updates carry a structured migrations[] entry and are skipped until you pass --major. The CLI prints the migration summary and any manual steps first.
  • Declared API migrations (a renamed prop, a moved slot) can be applied to your Blade views by ui:migrate <item> --dry-run, then --yes. Manual steps land in a report under .jml/migrations.
  • Experimental and incubating items can break on any version increase; their updates need --accept-unstable.
  • Downgrades are a hazard, not an update: a registry behind your project would revert component code and can strip props your templates use. They are skipped unless you pass --allow-downgrade.
terminal
php artisan ui:update data-table --major
php artisan ui:migrate data-table --dry-run
php artisan ui:outdated --fail

Note

In CI, ui:outdated --fail rejects a build with outdated or deprecated items and ui:check --offline --fail-on=warning lints your views against the installed component contracts. The full option reference is on the CLI page.