The dev command discarded the reload result, so a node author saw a
clean compile next to an editor that never updated. triggerReload now
returns the reason, and the help line shows it.
Wait on /healthz/readiness instead of /healthz, which answers before
the controllers are registered and so 404s the reload that follows.
Watch every top-level directory the build copies assets from, rather
than a fixed list of three, so an icon outside nodes/ is not copied at
startup and then ignored. The ignore list is now shared with
copyStaticFiles, so the two cannot drift apart.
Use a VERSION placeholder in the --n8n-image examples, because the
pinned release predates the reload endpoint.
The dev container mounted one fixed volume regardless of --n8n-image.
n8n only migrates a database forward, so testing against an older
release after a newer one pointed that older n8n at a database it
cannot read.
Narrowing the static asset watcher to the directories that exist at
startup dropped the one property the previous recursive watch on the
project root had: a directory created later was still picked up. A
project that adds its first root icons folder mid-session got no
watcher, so new SVGs were not copied or reloaded until restart.
Watch the project root non-recursively when an asset root is missing,
and attach the real watcher once it appears. That costs a single
descriptor rather than one per subdirectory.
The assertion matched a substring of the joined arguments against the
fixture's tmpdir. On macOS cwd resolves the /var symlink, so it compared
/var/... against /private/var/..., which still passed only because one is
a prefix of the other. It also passed for any other mount source ending
in the same path.
- Pass spawn arguments as an array instead of through a shell, so a project
path holding $, a backtick, ; or & reaches the child intact. Windows keeps
a cmd.exe invocation because package managers are .cmd shims, with every
argument quoted.
- Bound the /healthz and /rest/dev/reload requests with abort signals. An
accepted-but-unanswered connection previously parked waitForN8n forever, so
its timeout meant nothing, and every compile leaked a pending reload promise.
- Watch only the directories that hold icons and schemas. Recursive watching
of the whole project registered watches before filtering them, which on
Linux can exhaust fs.inotify.max_user_watches.
- Derive the published port from the parsed --n8n-url. An implicit port made
the mapping disagree with the URL used for readiness and reload, so the
container never became ready.
- Push one reload once n8n answers. The first clean compile can finish before
n8n serves the reload endpoint, leaving the node absent until the next edit.
Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Declan Carroll <declan@n8n.io>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: Michael Kret <michael.k@radency.com>