Berth

Dev versions

This is the part I use most. Every app has a dev version at https://<app>-dev.<your domain>, a place to try changes before they're committed. It's built so coding agents can test their own work. From the app's repo:

berth dev:push

That deploys the working tree exactly as it is on disk, uncommitted edits and new files included (.gitignore is respected, so .env and node_modules stay out). Your branch, index and stash aren't touched. A small change is live in about 5 seconds. Production is never affected; it still only deploys from pushes to its branch.

For agents, dev:push waits until it's done and has useful exit codes:

Exit code Meaning
0 live
1 the build failed (output above)
2 it built but didn't start (its last log lines are above)
3 the release command failed, e.g. a migration

--json prints the result (status, stage, url, release, the base commit and a summary of what's uncommitted) on stdout, with progress on stderr. A failed push leaves the previous dev release serving.

berth dev:agents myapp prints a block for the repo's AGENTS.md that tells an agent how to deploy, read logs and get in. Apps made with berth new already have it.

Who can reach it

Dev versions run unreviewed code, so they're not public. With sign-in set up they're open to the @owners group (berth auth:group owners [email protected]); without it, they're LAN only. Agents can't click through Google, so give them a token:

berth dev:token myapp --as [email protected]     # prints export BERTH_DEV_TOKEN=…
curl -H "Authorization: Bearer $BERTH_DEV_TOKEN" https://myapp-dev.example.com/api/me
berth dev:token myapp --revoke                  # revoke them all

With --as, requests are signed in as that pretend user (X-Berth-User-Id: dev:[email protected]), so an agent can test the signed-in parts of the app too. Tokens only work on dev versions and previews.

Its data is its own

A dev version never touches production's data:

  • Postgres: its own database (<db>_dev) in the same Postgres, with a login that can't connect to production's. It starts empty. berth dev:db:copy myapp replaces it with a copy of production's and runs the release command on it.
  • Redis: its own small Redis.
  • Storage: its own folders.
  • Config: copied from the app when the dev version is first made, minus the database URLs. API keys come along. Change it with berth config:set myapp-dev KEY=value.

It's just another app

The dev version is the app myapp-dev, so every command works on it: berth logs myapp-dev -f, berth run myapp-dev npm run migrate, berth restart myapp-dev. It keeps 3 releases, and it doesn't run scheduled jobs.

To save memory it goes to sleep after 12 hours with no pushes and no requests, and the next dev:push wakes it up. Change that with dev_idle_hours in ~/.berth/config.json.

berth dev:reset myapp deletes the dev version and its data, so the next push starts fresh from the app's current config. berth dev:off myapp removes the dev address altogether.

On your laptop, berth dev:push in the repo sends the snapshot to the Mac over SSH and deploys it there, with the same exit codes and --json. See Working from your laptop.

Edit this page on GitHub (it's a section of the README)