Your app is a database you can npm install
Here's a party trick that's actually an architecture: take any vibe you own — say a guestbook app running at vibes.diy/vibe/you/guestbook — and run this on your laptop:
jsimport { fireproof } from "use-vibes";
const db = fireproof("messages", { appSlug: "guestbook" });
await db.put({ text: "hello from Node", at: Date.now() });
db.subscribe((changes) => {
console.log("someone wrote from the browser:", changes);
}, true);
That's the whole program. The put shows up in every open browser tab of the app, live. A visitor tapping a button in the app lands in your script's subscribe a beat later. Same database, two peers, both directions — no REST endpoint to design, no schema to migrate, no glue service in the middle.
The mental model: a resident app and visiting peers
The way to think about it: your deployed vibe is the resident — the always-on peer that owns the data and serves every browser. Your script is a transient peer that drops in, does its job, and leaves. Cron job that summarizes the day's entries? Transient peer. Importer that backfills three years of CSV? Transient peer. A long-running monitor that watches for a particular document and fires off an email? A transient peer that happens to stay a while.
Get posts like this in your inbox
One email field. Real updates. No algorithm required.
There's exactly one rule that makes the connection work: use the same bare database name your App.jsx uses. The server routes on the triple (owner handle, app slug, database name) — nothing gets prefixed or namespaced on your behalf. If the app says fireproof("messages"), your script says fireproof("messages", { appSlug: "guestbook" }) and you're in the same room.
No keys to leak
The part that usually makes "connect a script to prod" annoying is credentials. Here it's one command: npx vibes-diy login enrolls the device with a certificate, and every script on that machine authenticates as you — request-signing under the hood, no API key to mint, copy into an env var, commit by accident, and rotate in a panic. Your access function sees your handle on every write, exactly as if you'd tapped the button in the browser. Which also means the permissions story requires zero new thought: the script can do whatever you can do in the app, and nothing more.
Two footguns, disarmed
We built a proof-of-concept against a real deployed vibe to make sure the docs tell the truth, and it surfaced exactly two stumbles worth naming:
- The option is
userHandle, notuserSlug. If you're connecting to an app under a different handle than your default, passuserHandle: "alice". The wrong key isn't an error — it's silently ignored, and you'll wonder why you're staring at an empty database. subscribehands you changed_ids, not full documents. It's a doorbell, not a delivery. Re-read withdb.get(id)to materialize the doc before acting on it.
Everything else behaves the way the browser API does, because it is the browser API — the same use-vibes package your generated app imports.
If you've been treating your vibe as "just a frontend," this is the door out: the full setup, the API table, and worked Node/Workers examples are in the Connect Backend Data guide. And if what you want is code running inside the platform — cron, webhooks, on-write triggers — that's backend.js, which speaks to the same database from the other side.
Your data, from anywhere JS runs
Build the app in a prompt, then script against its live database from Node, Deno, Bun, or a Worker.
Start building →