Versioning
Every deploy is an immutable version identified by a hash of its content; a single live pointer selects which version a site serves, moved by update and rollback.
Every deploy produces a version: an immutable snapshot of the site's content. A site has one live pointer that selects which version it serves. Deploying, updating, and rolling back are all just operations on versions and that pointer.
Content-hashed version ids
A version_id is the first 16 hex characters of the SHA-256 hash of the
deploy's content (every file's name and bytes, after Markdown rendering). The id is derived entirely from what you uploaded, which
makes deploys idempotent:
- Identical content always produces the identical version id.
- A redeploy of unchanged content stores no duplicate. The existing version
is reused, no files are re-stored, and
flypod versionsdoes not grow. flypod updatestill uploads and still reports the version as live. There is no "nothing changed" message — the deduplication happens server-side, on the hash, and is invisible from the command line.
This makes flypod update safe to call on every iteration of a loop: a run
that changes nothing costs an upload and produces no new version.
Versions are immutable
Once stored, a version never changes. There is no "edit a version"; you only
ever create new ones. Every deploy and every update creates a version, unless
a version with that content hash already exists — in which case that version is
reused.
The live pointer
A site serves exactly one version at a time: the one its live pointer references. The serve plane reads this pointer to pick which files to return, and embeds the live version id in the ETag.
Two commands move the pointer:
| Command | Moves the live pointer to |
|---|---|
flypod update | The newest version (deploying first if content changed) |
flypod rollback | The previous version, or any version still in history |
Update vs rollback
flypod update ships forward: it deploys the current folder as a new version
(or reuses an existing one) and points the site at it.
flypod rollback moves the live pointer back to the version before the live
one, or to any version you name with flypod rollback <version_id> (a unique
prefix is enough). Rolling back deletes nothing: the versions you rolled
past still exist, so you can roll forward again. List the history, newest
first, with flypod versions.
Because rollback only moves a pointer, it is instant and reversible — within the retention window below. The version you're "leaving" is not removed by the rollback; rolling forward re-points the site to it.
Retention
The garbage collector deletes every version that is not live once it is more than 7 days old (counted from when it was first stored), on anonymous and owned sites alike. The live version is never collected, however old it is. So the history you can roll back to, and that the timeline shows, is the live version plus whatever else was deployed in the last week.
The version timeline
Rolling back changes the site for everyone. The timeline lets one visitor look at an earlier version without changing what is live.
It is off unless you turn it on, because it makes versions you replaced public again:
flypod ./dist --timeline # a new site with History on
flypod update --timeline # turn it on with the next deploy
flypod versions --timeline # turn it on now, without deploying
flypod versions --no-timeline # turn it off--history and --no-history are accepted as the same flags. It can also be
switched from the History row on each site's card on your
account page, and from a chat app with the
configure_timeline tool.
flypod versions shows whether it is on. With it on, the command also prints
the compare link, and flypod versions --json carries history_url and a
url for each version.
With it on, the site's pages carry a small History chip in the bottom corner. It opens a list of the site's versions, newest first, each with its page title and when it was deployed ("12 min ago", "Today 11:30", "Yesterday 10:02", then the weekday, then the date). Choosing one opens it, and the list stays open so the next one is a single click, or an arrow key and Enter.
Each version is served at an address of its own, which you can also send to someone:
https://<site_id>.flypod.page the live version
https://<site_id>--<version_id>.flypod.page one versionBecause it is a separate address, every link and file on an old page stays
inside that version. Those addresses are served noindex, carry no comments,
and exist only while the timeline is on: turn it off and they stop answering.
The live site is served exactly as it is without the timeline.
Comparing two versions
https://<site_id>.flypod.page/_flypod/history (the Compare link in the
chip) puts two versions on one screen. Pick the two, then a layout:
| Layout | For |
|---|---|
| Side by side | A change of content or structure |
| Stacked | The same, for wide pages |
| Swipe across, swipe down | One version over the other with a divider to drag, for small visual changes |
The two scroll together, and following a link in one takes the other to the same page. The versions, layout and page are in the address, so a comparison can be shared as a link.
Versions that are not live are removed after seven days (see
Retention), so the timeline covers about a week of work.
<meta name="flypod" content="none"> in a page keeps the chip off that page.
How it works
flypod has two planes. A deploy pipeline ingests a zip into an immutable version, and a serve plane routes a subdomain to that version's files.
Ephemerality & TTL
Anonymous deploys expire 14 days after deploy and are swept by a garbage collector within minutes; deploying while logged in or claiming a site makes it permanent.