Edit .vue pages in a running Nuxt app, nothing installed
nuxt dev accepts no config path, so PortBay extends your app with a generated Nuxt layer instead — one that contributes a source-location plugin and leaves your own config alone. Nothing to install. Pro, early access, opt-in.
How do I edit a Nuxt page visually without installing anything?
Editing a Nuxt page visually needs a rendered element to carry a coordinate back to the .vue file behind it, and that means getting a plugin into Nuxt's Vite pipeline. Nuxt makes this awkward: nuxt dev has no --config flag at all, so a config file cannot simply be handed to it. PortBay uses the flag Nuxt does have, --extends, which takes a layer whose own nuxt.config is merged underneath your app's. The layer contributes one plugin under vite.plugins and lives in PortBay's data directory, so nothing is added to your repo and nothing of yours is replaced — Nuxt merges layers by concatenating arrays, so your own plugins keep working. Nuxt renders on the server, and the coordinates arrive in the served HTML. The editor is Pro, in early access behind a Settings opt-in, and absent from the open-source build.
Verified against the product, 2026-09-05.
A Nuxt app, extended by a layer
PortBay runs your Nuxt project at its own .test URL with trusted HTTPS and dispatches board cards into it. The visual editor edits that same running app in your real browser — one live page, not a multi-frame design canvas.
Your first Nuxt page edit
Four steps, none of which touches your dependencies. The layer is created before the dev server starts and deleted with nothing of yours attached.
- Install PortBay and add your Nuxt project
- Turn the visual editor on
- Start the project — the layer goes on automatically
- Open Edit in browser and change something
Install PortBay and add your Nuxt project
Homebrew installs the app and the bundled portbay CLI. Add the project folder and PortBay recognises Nuxt from your package.json, runs its dev server, and serves it at its own .test hostname over trusted HTTPS.
brew tap portbay-app/portbay && brew install --cask portbayTurn the visual editor on
It ships to Pro under early access and is off by default. Sign in to Pro, then flip the Early Access toggle. The open-source build does not include the editor at all — it is not compiled in.
Settings › Account › Early AccessStart the project — the layer goes on automatically
PortBay writes a tiny Nuxt layer into its own data directory and appends --extends to your dev command. The layer contributes one Vite plugin and pins the plugin's root to your project, which matters on Nuxt 4 because Nuxt points Vite at srcDir rather than the project root. Your nuxt.config is loaded by Nuxt itself and never rewritten.
portbay start myappOpen Edit in browser and change something
The project's Visual editing section has one button. It opens your normal browser at your normal .test URL with the edit bar docked at the top, booting in Preview mode where the page stays fully interactive. Switch to Edit, double-click text to type into the live page, then Save to write it into the .vue file. Your Tailwind design tokens are editable from the same rail, and renaming one rewrites every class that references it across your markup in one save.
https://myapp.testThe seam Nuxt gives you, and the one it doesn't
Every other framework on this lane takes a config path. Nuxt does not, which is why it has an injection family of its own — and why the mechanism is worth seeing rather than trusting.
Measured on served HTML rather than inferred from the config: the same project without the flag returns 1677 bytes and zero stamps, with it 1914 bytes and five real coordinates.
# nuxt dev has no --config. nuxi dev v3.37.0 accepts:# --cwd --dotenv --envName -e/--extends --logLevel --port --host --https # so the seam is a LAYER, not a config file:npm run dev -- --extends '<portbay data dir>/loc/projects/<id>/portbay-layer' # the layer's whole nuxt.config.mjs:export default { vite: { plugins: [portbayLoc({ root: '/Users/you/code/myapp' })] },}; # root is not optional here. Nuxt 4 points Vite at srcDir — <project>/app —# so without it every coordinate silently loses its app/ prefix:# app.vue:2:3 <- resolves against nothing# app/app.vue:2:3 <- what writeback needs # and your own plugins survive: Nuxt merges layers with defu, which# CONCATENATES arrays. The resolved list reads portbay:loc,user:marker.
The pieces underneath
Visual editor
Click an element on your running site in your own browser and edit its text, classes and styles straight into the source file, across 21 stacks.
Explore →HTTPS + .test domains
https://name.test per project: mkcert certificates, managed local DNS and a bundled Caddy edge, with expiry and reissue in view.
Explore →Asked before downloading
No. The plugin ships inside the PortBay app, is written to PortBay's own data directory, and reaches Nuxt through a generated layer passed with --extends. Nothing is added to package.json, node_modules or nuxt.config, and removing PortBay leaves all three byte-identical. There is no npm package for this, because nothing needs to serve one.
No, and this was checked rather than assumed, because a generated config being silently ignored is a failure this lane has produced before. Nuxt merges layer config with defu, which concatenates arrays instead of replacing them. Re-run with a logging plugin in the project's own nuxt.config.vite.plugins and PortBay's in the layer, the resolved plugin list contained both and every stamp was still present.
Nuxt 4's app/ directory would break them, if the plugin were left to guess. Nuxt 4 points Vite at srcDir, which is <project>/app rather than the project root, so a plugin falling back to Vite's own root produces coordinates like app.vue:2:3 where the real file is app/app.vue. PortBay's layer passes the project root explicitly for exactly this reason. That was measured by removing the option and watching every coordinate lose its app/ prefix while still looking plausible.
Yes, and that is the point of measuring it on served HTML rather than in a client bundle. Nuxt renders on the server, and the source coordinates come back in the HTML the browser receives — verified with two runs of the same project differing only in the flag: 1677 bytes and zero coordinates without it, 1914 bytes and five with it, naming real files and lines in app/ and app/components/.
Yes, through the Page settings panel, which reads and writes the useHead() call in that page's own <script setup>. Because useHead() is per-component, the values genuinely belong to that route and nothing else — so a title written there cannot leak onto another page. If the route has no useHead() call yet, one is created rather than the value being written somewhere it would not take effect.
Because the minimal scaffold's app.vue is a single <NuxtWelcome /> tag, and that component's markup lives in node_modules/nuxt/dist. PortBay refuses to hand you a coordinate pointing into a dependency, so a completely untouched scaffold stamps nothing — not because the lane failed, but because the project contains no markup of its own yet. Add one real page and the coordinates appear.
No. It is a Pro feature, still in early access behind an opt-in toggle in Settings, and it is not compiled into the open-source build at all. It also refuses to run while the project is shared over a public tunnel, and the edit bar only works on local .test hosts. Running your Nuxt dev server on a real .test domain with trusted HTTPS is in the free, open-source app.
Yes. Vue is one of the four formats where that structural edit is supported, so an element in a .vue page can be moved into its own component file, with the import added and the original span replaced by the new tag, in one save. It refuses by name in one case: a span carrying a template expression is not extracted, because the expression's page-local values would not exist in the new file and the result would be markup that looks right and does not compile.

Give your projects and your agents a real local home.
Download for macOSFree & open source · macOS 11+ on Apple Silicon · Pro from $10/mo