What is Vaporware?
A local Vapor development environment for macOS.
Vaporware is a native macOS app that runs your Vapor projects locally — no terminal wrestling with swift run, no Docker configs, no manual database setup. Open the app, point it at a project, and it just works.
It runs as both a window app and a persistent menubar utility. Close the window and your services keep running; quit from the menubar for a clean shutdown.
What’s included
- One-click projects — open or create a Vapor project and run it instantly.
- Bundled databases — PostgreSQL, MySQL, SQLite and Redis with no Homebrew or Docker.
- Pretty domains — reach your app at
myapp.testwith automatic HTTPS. - Log viewer, environment editor, and a built-in mail catcher.
New here? Help ▸ Show Welcome reopens the first-launch tour any time.
First Launch
What happens the first time you open the app.
The first thing Vaporware shows is its license agreement. Read it in the window and press Agree and Continue to go on, or Quit to close the app — Vaporware is free, but using it means accepting the license. You can re-read it any time in Settings ▸ Legal, which also records the version you accepted and when. If a future update revises the agreement, you’ll be asked once more.
After that Vaporware sets itself up and shows a short welcome tour. A menubar icon appears and stays available even when the main window is closed.
If you launch the app straight from the downloaded disk image or your Downloads folder, Vaporware offers to move itself to the Applications folder first — running from a stable location keeps self-updates and login items working. Accept the move and it relaunches from Applications automatically.
Installing databases
Database engines aren’t bundled into the download — they’re fetched on demand and verified, so the app stays small. Open Services in the sidebar to install PostgreSQL, MySQL or Redis. Each shows a Recommended badge on the latest supported version.
SQLite needs no install — it’s file-based and always available.
Keeping Vaporware Updated
Built-in updates — no App Store needed.
Vaporware updates itself. By default it checks for new versions in the background and offers them when they’re ready — release notes included.
- Help ▸ Check for Updates… checks on demand.
- Settings ▸ General ▸ Automatically check for updates turns background checks on or off.
Updates are free for everyone — Vaporware has no paid tier and no license keys.
Notices
The bar across the top of the window, and what it’s telling you.
When something needs your attention — yours or the app’s — it appears in a bar across the top of the window, with a button that fixes it where there is one. If more than one thing is waiting, page through them with the ‹ › arrows; the most urgent is shown first.
Three kinds
- Blocking — Vaporware can’t do its job until this is resolved, so it can’t be dismissed. Fixing the problem clears it.
- Attention — something is degraded and you can fix it, like a daemon running an older build. Dismiss it to get on with what you were doing; it comes back next launch if the problem is still there.
- Informational — worth knowing, like an available update. Dismiss it and it’s gone for good.
Notices track what’s actually true right now rather than piling up: fix the problem and the notice disappears on its own, without you clearing anything.
Dismissed something you want back? Settings ▸ General ▸ Notices ▸ Show Again restores them.
Services
One screen for everything Vaporware runs that isn’t a single project.
Services sits at the bottom of the sidebar, below your projects. Everything on it is app-wide rather than about one project, and everything on it is something you do — install, start, stop — rather than something you set.
What’s on it
- Engines — PostgreSQL, MySQL and Redis, downloaded on demand and verified. Install, move to another version, or remove one. SQLite needs nothing installed.
- Databases — every database on your Mac, not just the selected project’s, with Start All / Stop All and the same per-database controls as a project’s Databases tab: browse data, back up, edit credentials, delete.
- Network Services — the DNS resolver, the HTTP and HTTPS proxies, and the
.testrouting switch. If another app holds a port Vaporware wanted, it’s named here with a Stop button. - Mail — whether the catcher is listening, and on which port.
The service dots at the bottom-right of a project’s window are the same facts at a glance; this is the screen behind them.
Preferences still live in Settings — which engine a new project gets, whether databases start at login, the mail port. Services is the live state and the buttons.
Backups and Routing sit beside it, on the same principle: every backup on this Mac in one place, and every .test domain being served with the project behind it.
Creating a Project
Scaffold a brand-new Vapor project.
Choose New Vapor Project… from the + menu to scaffold a fresh Vapor app. Vaporware writes a modern Package.swift, an entrypoint.swift, configure.swift and routes.swift, ready to run.
- Give it a name and a folder. New projects default to
~/Vaporware— a local projects folder with the Vaporware icon — but any location works, and your last choice is remembered. - Pick the options you want (below).
- Click Create Project. It appears in the sidebar and is ready to start.
Options
- Provision Database — create a PostgreSQL, MySQL or SQLite database and pre-fill
.envwith its credentials in one step. - Enable Redis — add a Redis instance for caching, sessions or job queues.
- Pretty Domain — reach the app at
name.test, optionally over HTTPS, instead oflocalhost. - Initialize Git Repository — run
git init, add a.gitignore, and make a first commit. On by default. - Friendly Error Pages — add Leaf and branded 404/500 pages so a blank project renders HTML instead of raw JSON. Off by default.
The first build fetches dependencies and compiles, so it’s slower than later builds. This is normal.
Opening an Existing Project
Add a Vapor project you already have.
Use Add Project to point Vaporware at an existing Vapor project folder. It detects the package, reads any .env, and lists it in the sidebar.
Select a project to see its detail view — server controls, databases, domains, environment variables and logs are all tabs there.
Running a Server
Start, stop and watch a project build.
Press Start in a project’s Overview to build and run it. The status moves through Starting → Building → Running as Vaporware tracks swift run output, and a status bar pinned across every tab keeps the controls in reach.
- Building shows compile progress parsed from the build output.
- Running appears once Vapor reports the server is listening, alongside uptime and the process ID.
- Restart rebuilds and relaunches; the console is collapsible and starts collapsed — expand it to follow build and request output.
Rebuild on Save
Swift is compiled, so an edit changes nothing until the server is rebuilt. Turn on Rebuild on Save in a project’s Overview and Vaporware watches the project’s Swift files: save one, and it rebuilds and relaunches the server for you. The Overview notes what triggered the last rebuild, and the console shows the build as usual.
- Only
.swiftfiles count. Leaf templates and files inPublic/are read from disk on each request, so they need no restart — and build output in.buildis ignored, which is what keeps a rebuild from triggering itself. - Saving several files at once costs one rebuild, not one per file.
- A build that fails leaves the watch running — fix the error, save, and it tries again.
- It’s per project and off by default, since a rebuild on a large project is real work. Stopping the server stops the watch.
Quick Actions
The Overview’s Quick Actions jump straight into your usual tools:
- Open in Browser — visit the running app at its domain or
localhostport. - Open in Editor / Open in Terminal / Show in Finder — open the project folder in your chosen editor, terminal, or Finder.
- Update Packages — run
swift package updatewith live progress, without leaving the app.
How the server is run
By default Vaporware runs a debug build in the app’s default environment. Both are yours to change in Project Settings › Run:
- Build — Debug is fast to compile and slow to execute; Release is the reverse. Switch to Release when you want to measure real performance, and expect a longer build.
- Environment — passed as Vapor’s
--env, whichconfigure.swiftreads to decide what to switch on. Blank leaves the app’s own default (development, unlessVAPOR_ENVsays otherwise). - Arguments — anything else you want on the command line, appended to
swift run.
The hostname and port stay Vaporware’s: it routes your .test domain to that port and shows it throughout the app, so a server that moved its own port would break both. Changes take effect the next time the server starts.
Turn on Auto-start server when project is opened in Settings, or Run server at login in a project’s settings, to bring servers up automatically.
Routes
Every route your app registers, from the app itself.
A project’s Routes tab lists every route the app registers — method, path, and a description where one is set. Filter by path or method, and double-click a plain GET route to open it in your browser while the server is running.
The list comes from the app, not from reading your source: Vaporware runs the same routes command Vapor gives you in a terminal. A route added by a controller, a route group, or a package you depend on is therefore in the list, and the list can never disagree with what’s actually serving.
- A path component shown as
:idis a parameter — there’s no single address to open, so those aren’t double-clickable. - Refresh re-reads them. The first read after an edit compiles the project, so it can take a moment.
- Routes can’t be read while a build is running: SwiftPM holds a lock on the build directory for the length of it.
Commands & Migrations
Run your app's own commands — migrations, workers — without a terminal.
A Vapor app registers commands of its own: Fluent adds migrate, the Queues package adds queues, and you can add your own. The Commands section on a project’s Overview reads that list from the app itself and offers to run them.
Press Read Commands and Vaporware asks your app what it can do. Whatever comes back is what you get — nothing is assumed on your behalf, so a command you added this morning is there, and a command your project doesn’t have never appears.
Migrations
If your project uses Fluent, migrations get their own controls:
- Run Migrations applies everything outstanding.
- Revert Last Batch— rolls back the most recent batch, after asking. Reverting runs your migrations’ own revert steps, so anything they drop is gone — take a backup first if the data matters.
Both run against the same database and environment the server uses, so a migration you run here is the one your app will see.
Output from the last command is kept underneath, so a failed migration’s error is still there after you switch tabs.
Swift Toolchains
Pick a Swift version per project.
Vaporware detects the Swift toolchains installed on your Mac (it does not bundle them — that’s Xcode’s job). Use the toolchain picker in a project’s settings to build it with a specific Swift version.
Your choice is recorded in a .swift-version file at the project root — the ecosystem standard — so other tools, including Pixla Editor, match their language server to the toolchain Vaporware builds with.
If a project is pinned to a Swift version that isn’t installed on this Mac, Vaporware builds it with the system default instead and says so in a notice — the fallback keeps the server running, but the compiler that built it is then not the one the project asks for.
Dependency Versions
See what a project actually builds against.
The Versions section of a project’s Overview answers a question that otherwise means opening two files: what is this project actually built against right now?
- Swift — the toolchain the server builds with: the project’s own pin if it has one, otherwise the system default, named with its version.
- Swift tools — the
// swift-tools-version:fromPackage.swift. This is the manifest format your package is written for, not the compiler it runs on. - Your dependencies — Vapor first, then everything else
Package.swiftdeclares. - Transitive dependencies — everything pulled in indirectly, folded behind a count. Click to expand.
Where the numbers come from
From Package.resolved, not Package.swift. The manifest states a range — from: "4.99.0" — while the resolved file states the exact build you actually get. A dependency pinned to a branch or a commit rather than a version shows its short commit hash instead.
A project whose dependencies have never been resolved says so rather than showing an empty list. Start the server once, or use Update Packages, and the versions appear.
The list refreshes when you switch projects, after Update Packages, and after a build — so it never shows you yesterday’s answer.
Checking for Updates
Find out which dependencies have newer versions.
Vaporware asks SwiftPM what a swift package update would actually change, and shows the answer in the Versions section. A dependency with a newer version available reads 4.122.0 → 4.122.1, with the new version in the accent colour.
Underneath, a summary line — “4 updates available” — expands to name every one of them. Expand it: an update to a transitive dependency counts toward that number but lives inside the collapsed list, so the summary is the only place you see the full set. Update Packages applies them all.
What it does and doesn’t cover
The check reports only the updates your Package.swift already allows. If your manifest says from: "4.99.0", a new major version is outside that range and will never appear here — taking it is a manifest edit, not an update.
The upside of asking SwiftPM rather than checking a website is that every update listed is one Vaporware can genuinely take. A version that some other dependency forbids is never offered.
Automatic checks
Vaporware checks your projects once a day on its own. When something is waiting, the project gets a badge in the sidebar and a notice appears at the top of the window with a Review… button that takes you to it.
Two things are deliberately left alone. A project you have never built is not checked — resolving its whole dependency graph over the network for something you haven’t opened would be rude. And a project that is currently building is skipped, because SwiftPM holds a lock on .build for the length of a build.
If you run the background daemon, the sweep happens there, so it keeps to its schedule with Vaporware quit and the answers are waiting when you next open the window. Without the daemon the app sweeps instead, whenever it’s running.
Settings ▸ General ▸ Dependency Updates has the frequency, an off switch, when the last sweep ran, and Check All Projects Now.
A background check that fails — you were offline overnight, say — leaves the last good answer in place rather than replacing it with “couldn’t check”. A check you ask for yourself tells you exactly what went wrong, because you’re waiting on it.
Reverting a Package Update
Put the previous dependency versions back.
Before every update, Vaporware saves the project’s Package.resolved — the file that records exactly which version of every dependency you build against. Revert Packages… in the Versions section lists the saved copies by date and package count; pick one and Vaporware puts it back and re-resolves against it.
The last ten are kept per project. They’re tiny, they live with Vaporware’s other state in Application Support, and they’re removed when you remove the project.
What a revert does and doesn’t do
- It rolls back dependencies, not your own code. Any source changes you made to suit a new API are still there — and may no longer compile against the older version.
- It forces a rebuild, since the checked-out sources changed underneath
.build. - It takes its own snapshot first, so a revert can itself be reverted.
- If you edited
Package.swiftsince the snapshot was taken, the old versions may no longer satisfy it. Vaporware tells you rather than quietly resolving to something you didn’t choose.
If your project is a git repository, git diff Package.resolved after an update shows the same information — exactly what moved, and by how much.
Organizing the Sidebar
Reorder projects and file them into groups.
Drag any project in the sidebar to put it where you want it. The order is yours — it isn’t alphabetical and it isn’t the order you added things in — and it’s remembered between launches.
Groups
Groups are folders in the sidebar for keeping related projects together. Choose New Group… from the + menu to make one. Projects inside a group are indented under its folder, so you can see at a glance what belongs where.
- File a project — drag it below a group’s row, or use Move to Group in its right-click menu.
- Take it back out — drag it above every group, back into the top list.
- Collapse a group — click the arrow on its row. Groups stay collapsed until you open them again.
- Move a whole group — drag its row; the projects inside come with it. Groups always sit below the ungrouped projects, and a group can only land beside another group, never inside one.
- Rename or delete — right-click the group’s row. Deleting a group never deletes projects: they move back to the top list.
Groups are a view of your projects, not a change to them — nothing moves on disk, and a project’s folder, database and domain are untouched by how you file it.
Renaming & Removing Projects
Rename, configure, or remove a project safely.
Each project has a Project Settings sheet (the gear in Overview) for its name, port, Swift toolchain, and whether its server starts at login. Right-click a project in the sidebar for Rename… and Remove Project….
Select several projects first — ⌘-click or ⇧-click in the sidebar, across groups if you like — and Move to Group and Remove… act on all of them. The removal sheet names every project it’s about and carries the same two opt-ins, so a batch is never a shortcut past the safeguards.
Renaming
Renaming moves the project folder and rewrites the package name in Package.swift. A running server is stopped and restarted automatically. The project’s .test domain and its database are unaffected by the move — they’re keyed to the port and the folder’s .env, not the folder name.
Removing
Remove Project takes a project out of Vaporware’s sidebar. By default nothing on disk is touched. Two opt-in choices let you clean up further:
- Drop the database — delete the linked PostgreSQL/MySQL database or SQLite file.
- Move project folder to Trash — remove the folder from disk entirely.
Leave both off to simply stop managing a project — your code and database stay exactly where they are.
Bundled Databases
PostgreSQL, MySQL, SQLite and Redis — no Docker.
Vaporware manages local database engines for you. Install them from Services in the sidebar, where you can also start and stop every database on your Mac at once — or one at a time from a project’s Databases tab or the menubar.
- PostgreSQL — default port
5432, default uservaporware. - MySQL — default port
3306, default uservaporware. - Redis — default port
6379. - SQLite — file-based, browse
.sqlitefiles with no server process.
Already running Postgres or Redis (e.g. via Laravel Herd)? Vaporware assigns each managed engine its own port to avoid clashing.
Managing a database
Each database row in the Databases tab starts and stops the engine and shows its status, port and connection string. Its ⋯ menu covers the rest:
- Open in Terminal — launch
psql,mysql,redis-cliorsqlite3connected to that database. - Copy Connection String / Copy Command — grab the URL or a ready-to-paste client command.
- Show Data in Finder — reveal the database’s data directory.
- Link / Unlink — associate a database with a project (writing its
.env), or detach it. - Browse Data… — open its tables and run statements inside Vaporware.
- Edit Credentials…, Back Up / Restore…, and Delete Database.
Browsing Data
Look inside a database without leaving Vaporware.
Browse Data— in a database’s ⋯ menu opens its tables: pick one on the left and its rows appear on the right. Right-click a row to copy it, or copy the whole result as tab-separated text for a spreadsheet.
A preview loads the first 200 rows and says how many the table holds in total, so a screenful is never mistaken for the whole table. To go further, type a statement in the box at the bottom and press Run (or ⌘-Return).
Editing rows
Double-click a cell to change it, Return to save, Escape to abandon. Right-click for Set to NULL or Delete Row…. Every write names the row by its primary key, and the table is re-read afterwards so what you see is what the database stored — not what was typed.
A table with no primary key is read-only, and says so under the rows. There is no expression that names one row of it: a WHERE over the values you can see updates every duplicate too, and a table without a key is exactly the kind that has them. The same goes for a result you got by running your own statement — its columns can be computed, aliased, or from several tables at once. Use the statement box for both.
- Anything you can write runs — it’s your database. A statement that returns rows shows them; one that doesn’t shows what the client reported, and the table list refreshes in case the schema changed.
- Reads go through the same client Vaporware would hand your terminal (
psql,mysql,sqlite3), so what you see is what the engine says. - Redis isn’t tabular, so it has no browser — use Open redis-cli in Terminal instead.
Passwords reach the client through its environment, never on the command line, so they don’t appear in the process list.
Auto-Provisioning
A ready-to-use database per project.
When you create a project you can provision a database in one step. Vaporware creates it and writes the connection details straight into your .env.
- SQLite — the file is written into Vaporware’s own storage and referenced by an absolute path, in
SQLITE_PATH(what Fluent’s.sqlite(.file(…))takes) andDATABASE_URL. Absolute because a relative path resolves against whatever directory the server was launched from — the project folder underswift run, somewhere else under Xcode — which is how a project ends up with two database files and your rows in the wrong one. - PostgreSQL / MySQL — runs
CREATE DATABASE project_name OWNER vaporware. - SQLite — creates a new
.sqlitefile in the project directory. - The generated
.envis pre-filled with the correct host, port, user and database name.
Generated code never hardcodes credentials — it reads them from the environment, e.g. Environment.get("DB_HOST").Username and password
By default a database is owned by the shared vaporware user with no password — local servers accept trusted connections, so nothing else is needed. To set your own, fill in Username / Password when adding the database, or use Edit Credentials… from a database’s ⋯ menu later. Vaporware creates the matching role and updates the linked project’s .env.
Local servers keep trusted auth, so a password is stored and used by your app but isn’t required to connect on your machine.
.test Domains
Reach your app at myapp.test.
Instead of localhost:8080, give a project a friendly .test domain. Vaporware runs a small DNS resolver and an HTTP reverse proxy so myapp.test routes to your running server.
- Open a project’s Domain tab and add a hostname like
myapp.test. - The first time, Vaporware asks for admin permission to register the
.testresolver. - Visit
http://myapp.test— the proxy forwards it to your app.
Domain routing is handled by an internal proxy — Vaporware never edits your /etc/hosts file.Network services
Routing in the sidebar shows the DNS resolver and HTTP/HTTPS proxies that make .test work, with switches to enable or disable .test routing. If another local tool (such as Laravel Herd) already holds ports 80 or 443, Vaporware lists the processes and offers to take over — or you can stop them yourself and retry.
Routing in the sidebar owns the machinery — the DNS resolver, the proxies, the .test switch — and lists every hostname being served with the project behind it. A project’s own Domain tab keeps just its hostname and one line saying whether it can be reached; the two have different names because they answer different questions.
Automatic HTTPS
Trusted local certificates for .test.
Enable SSL on a domain and Vaporware issues a certificate from its own local certificate authority, then serves your app over https://. The CA is added to the system trust store so the browser shows a valid lock.
These certificates are for local development only and are never used in production.
Mail Catcher
Catch outgoing email during development.
Vaporware includes a local SMTP catcher. Point your app’s mail at the catcher and every message it sends is captured and shown in the Mail inbox instead of being delivered for real.
- Listens on SMTP port
1025by default (configurable in Settings). - Captured messages are saved as
.emlfiles and persist across launches. - Inspect headers, body and recipients without sending anything to a real inbox.
Set your app’s SMTP host tolocalhostand port to the catcher’s port —MAIL_HOSTandMAIL_PORTin most projects — to start catching mail.
With the background daemon enabled the catcher runs there, so mail sent by a server the daemon started at login is captured even with Vaporware quit — open the window later and it’s waiting, with anything new arriving as it lands. Without the daemon the app catches mail whenever it’s running.
The inbox
Open Mail from the sidebar to read what’s been caught. Search across messages, and clear the mailbox when you’re done.
- View each message as rendered HTML, plain Text, or raw Source.
- Inspect the From / To / Cc / Date headers and save any attachments.
- Delete a single message, or use Clear All to empty the inbox.
- Drag the divider between the list and the message to resize the panes; the width is remembered.
Links in a captured message open in your default browser rather than loading inside the message pane — following a password-reset link takes you to your app, and the email stays put. Captured mail is untrusted input, so only http, https and mailto links are followed.
Environment Variables
Edit per-project .env values visually.
Each project’s Environment tab is a visual editor for its .env file. Add, edit and remove variables without leaving the app; changes are written back to .env.
When you provision a database, its connection variables appear here automatically.
- Toggle a variable off to comment it out (
#) without deleting it, and reorder rows by dragging. - Add a comment to any variable to document what it’s for.
- Import from .env to pull in an existing file, or Export .env… to save the current set.
- Duplicate keys are flagged — the last value wins — and a deleted row can be restored with Undo Delete.
Logs
Watch requests and errors in real time.
The Logs tab streams your server’s output as it runs — incoming requests, route matches and errors. Use it to debug routing and inspect failures without switching to a terminal.
- Each request row shows the method, path, status code and duration, colour-coded so failures stand out.
- Filter by HTTP method or by path to focus on a route, and Clear to reset the view.
- Export copies the log to the clipboard, or saves it as text or CSV — whatever the filters are showing is what you get, so you can narrow it down first.
The Console section on a project’s Overview holds the server’s raw output. It shows the last 100 lines; the copy button next to it takes all of them, which matters because the build failure you want to paste into a bug report is usually the part that scrolled off the top.
Database Backups
Snapshot and restore your local databases.
Vaporware can snapshot your PostgreSQL and MySQL databases on a schedule or on demand, and restore any snapshot when you need it. Backups live under Application Support ▸ Vaporware ▸ Backups.
Backups in the sidebar shows every backup on this Mac at once — what exists for each database, when the last scheduled run was, and a Back Up Now for one or Back Up All for everything. Restoring is there too, behind a confirmation, because a restore replaces what the database currently holds.
Automatic backups
Open Settings ▸ Backups and turn on Back up databases automatically. Choose how often to run and how many recent snapshots to keep; old ones are pruned for you.
- Frequency — every 6 hours, daily, or weekly.
- Retention — keep the N most recent snapshots per database.
- Back Up All Databases Now runs a full pass immediately.
Where the schedule runs depends on who is managing your services. With the background daemon enabled it runs there, so backups happen with Vaporware quit; otherwise the app runs it, which means any time Vaporware is open — the menubar counts. The Backups screen names whichever it is, beside the last run.
Backing up one database
From a database’s ⋯ menu, choose Back Up / Restore…. You can snapshot it, restore an earlier snapshot, or Restore from File… using a .sql dump created elsewhere.
Backups cover the server engines only. SQLite is already a file you can copy, and Redis is a cache — neither is backed up here.
Exporting Projects & Settings
Take a project, its .env, or your settings elsewhere.
Vaporware can hand a project or your app configuration off to another machine or teammate.
- Export as .zip — from a project’s Overview, package the project folder, excluding
.gitand.build, ready to share. - Export .env… — save a project’s environment variables as a
.envfile from the Environment tab. - Export Settings… / Import Settings… — in Settings ▸ Backups, move your Vaporware preferences between machines as JSON.
Exported settings never include your Pixla Hosting API key — that stays on the machine where you entered it.
The vw Command
Drive Vaporware from the command line.
Vaporware ships a companion vw command-line tool for scripting and quick checks from the terminal. It talks to the same services the app manages, so anything you can do in the window you can do from a script.
vw status # service and project status vw status --watch # live-updating status vw doctor # diagnose common problems
Command groups
vw project—list,new,add,removeprojects.vw server—start,stop,restart,status, andlogs --followfor a project.vw db—list,create,provision,start,stop,removedatabases.vw env—list,set,unseta project’s environment variables.vw domain—add/removea.testdomain;vw dns,vw proxy,vw routingcontrol the network services.vw sites—resynca project generated from a Pixla Sites document, from its own.pxs.vw daemon—start,stop,status,install,uninstallthe background daemon.
Add --json for machine-readable output. Each command group has its own --help, and vw completions zsh (or bash) prints a shell-completion script.
Where it lives
The app links the commands into ~/.local/bin — vw, plus vaporware as a longer alias for the same tool and vaporwared for the daemon. If your shell can’t find vw, that folder isn’t on your PATH; add it to your shell profile, or run vw daemon install --prefix <dir> to link them somewhere that is.
Background Daemon
Keep services running without the app open.
Vaporware can run a headless daemon (vaporwared) that owns the managed services. With the daemon enabled, your databases, proxy and domains keep running even when the app — and its window — are closed, and the vw CLI talks to the same daemon.
Enable it under Settings ▸ General ▸ Background Daemon, and optionally Start daemon at login so services are up before you open the app. When the daemon is off, the app manages services in-process instead; ownership hands off cleanly between the two so they never fight over ports.
- Prefer the terminal?
vw daemon installsets up the login item and CLI tools;vw daemon uninstallremoves them. - After an app update the daemon can lag behind — the app shows a Restart Daemon prompt to bring it up to the new build.
Work that carries on without you
The daemon doesn’t only hold services open — it does the work that has no business waiting for a window to be on screen.
- Automatic backups run on their schedule with Vaporware quit — which is the point, since the night you most want a snapshot is one you slept through.
- Dependency-update checks sweep on their schedule too; open the window later and the results are already there.
- The mail catcher keeps listening, so a server the daemon started at login can still send mail and have it caught.
With the daemon switched off, all three belong to the app instead. They run whenever Vaporware is running — closing the window is fine, since it stays in the menubar — but quitting stops them until you next open it.
One owner at a time
Exactly one process owns your services and your project list — the daemon when it’s running, the app otherwise. If a second copy of Vaporware opens and can’t reach the one already in charge, it says so in a banner and stays read-only rather than competing with it. That’s deliberate: two owners would each save their own copy of your project list over the other’s.
Publish to Pixla Hosting
Hand a project off to production hosting.
Vaporware is a local development tool, not a deployment platform. As a convenience — like Xcode’s Upload to App Store Connect — it can package a Vapor project and hand it off to Pixla Hosting, which takes over container provisioning, TLS and routing.
- Paste a Pixla Hosting API key once in Settings ▸ Integrations — mint one at app.pixla.app.
- Click Publish to Pixla Hosting in the project’s Overview.
- Choose a subdomain — your app goes live at
yourname.pixla.app. - Vaporware packages the project, uploads it, and streams the remote build; Pixla Hosting handles the rest.
Server options
Expand Server options before publishing to size the deployment. Vaporware picks sensible defaults, so you can also just publish.
- Size — from 512 MB / 1 shared CPU up to 8 GB / 4 performance CPUs.
- Region — where it runs, from Ashburn to Frankfurt, Tokyo or Sydney.
- Machines — run more than one for redundancy, and keep them Always-on.
- Dedicated IPv4 and Add a database when the app needs them.
Re-deploying
Publish again to an existing subdomain and Vaporware recognizes it and offers Re-deploy. If a previous deploy got stuck, Reset & Retry clears it so you can publish cleanly.
Don’t use Pixla Hosting? You’re not missing a core feature — Vaporware’s value is local development. Publishing is purely optional.
Pixla Sites Export
Turn a Pixla Sites project into a Vapor app.
If you use Pixla Sites, the no-code builder, Vaporware can convert a Sites project into a deployable Vapor 4 app. Choose New from Pixla Sites… from the + menu (or open a .pxs file) and confirm a name.
Pages become Leaf templates over a shared layout, forms become dynamic routes backed by Fluent, and fonts and images are copied into Public/. The generated project is ready to run locally just like any other, with branded error pages included.
Re-syncing from Pixla Sites
Update a generated project as the design changes.
Export isn’t one-way. When a project was created from Pixla Sites, its Overview shows Re-sync Design — regenerate the Leaf templates and assets to match the latest Sites design without clobbering the server code you’ve written.
- Design files — Leaf templates and
Public/assets are regenerated every sync, and orphans are pruned. - Your code —
routes.swift,configure.swift, your own controllers and models are written once and then left alone. - Re-sync previews what will change first. If it detects a hand-edited design file, choose Keep My Edits or Overwrite All.
If a Sites page gains or loses a form, the project may need Fluent wiring that re-sync won’t add in place — the sheet flags this so you can regenerate deliberately.
From the terminal
vw sites resync <path> does the same thing without opening the app — useful in a script or a release step. It reads the source document from the project’s own .vaporware/pixla-sync.json, so a path is all it needs and the daemon doesn’t have to be running.
vw sites resync ~/Vaporware/MySite --dry-run # list what would change vw sites resync ~/Vaporware/MySite # apply, keeping your edits vw sites resync ~/Vaporware/MySite --overwrite-conflicts
Troubleshooting
Common issues and quick fixes.
A database won’t start
Another process may be holding its port. Vaporware tries to free orphaned processes on startup, but if a clash persists, check what else is using the port (e.g. Laravel Herd) and stop it, or restart the app for a fresh port assignment.
The first build is very slow
A project’s first build resolves and compiles every dependency. Subsequent builds reuse that work and are far faster.
A .test domain stopped resolving
Quit and reopen Vaporware so it re-registers the resolver. The app pins the DNS port recorded in the system resolver to keep .test stable across restarts.
Ports 80 or 443 are already in use
Another local tool — often Laravel Herd — may hold the HTTP/HTTPS ports. Routing lists the conflicting processes and offers to take over the ports, or you can stop that tool and click Retry.
Uninstalling Vaporware
Remove the app and clean up everything it installed.
Vaporware installs a few things outside its app bundle — a .test DNS resolver and firewall redirect, a local HTTPS certificate, CLI tools, and a data folder. The built-in uninstaller undoes all of it for you.
The easy way
Open Settings › General and click Uninstall…. Choose what to remove (including whether to delete your local databases), and Vaporware tears it all down — disabling .test routing, removing the HTTPS certificate, deleting the CLI tools and login item, and clearing its data — each with a prompt where one is needed.
When it finishes, drag Vaporware from your Applications folder to the Trash. (An app can’t delete itself while it’s running, so this last step is manual.)
Prefer the terminal? Runvaporware uninstallfor the same thing, orvaporware uninstall --keep-datato remove everything except your databases. Add-yto skip the confirmation.
What gets removed
.testrouting — the DNS resolver and firewall redirect (restoring any resolver that was there before).- The Vaporware Local CA HTTPS certificate, from your login keychain.
- The
vw/vaporwareCLI tools and the background-daemon login item. - All local data — every PostgreSQL, MySQL, Redis and SQLite database, downloaded engine binaries, and logs (
~/Library/Application Support/Vaporware).
Your project folders and their .env files are never stored here — they stay wherever you created them and are left untouched.Removing things by hand
If you ever need to clean up manually — for example after deleting the app first — these are the locations involved:
- Data —
~/Library/Application Support/Vaporware - Login item — the Vaporware entry in System Settings › General › Login Items & Extensions (turn off “Start daemon at login” in Settings to remove it). CLI installs instead use
~/Library/LaunchAgents/app.pixla.vaporwared.plist. - CLI tools — the
vw,vaporware,vaporwaredsymlinks in~/.local/bin - HTTPS cert — Vaporware Local CA in the login keychain (Keychain Access)
.testrouting —/etc/resolver/test,/etc/pf.anchors/com.vaporware,/Library/LaunchDaemons/com.vaporware.pf.plist, and/Library/PrivilegedHelperTools/com.vaporware.pf.sh(plus acom.vaporwareline in/etc/pf.conf)
Contact & Links
Reach support and find more.
Need a hand or want to learn more?
- Website — vaporwareapp.com
- In the Pixla family — pixla.app/vaporware
- Support — support@pixla.app
- Legal — License (EULA), Privacy Policy & Third-Party Notices. The license and the acknowledgments are also in the app, under Settings ▸ Legal — the acknowledgments list the open-source components Vaporware includes and the database engines it has downloaded to this Mac.
The Help menu has Report a Bug… and Send Feedback… — both open a message pre-filled with your version and system details. About Vaporware and Check for Updates… live in the app menu, and the bundled licence is readable under Settings ▸ Legal.
Vaporware by Pixla.