---
title: Drafts, revisions and publishing
description: How an entry moves from a draft to a published page, and what Hollware keeps along the way.
section: concepts
order: 2
---

# Drafts, revisions and publishing

An entry is one page in one locale: a collection, a locale and a slug. Its content is a list of **revisions**.

## Revisions

Every `create_draft` and `update_draft` adds a revision: the whole Markdown file, frontmatter included, exactly as it was sent. Revisions are never changed or deleted, so you can always see what an entry said, and when.

An entry has a **version**, which goes up with every change. `update_draft` takes the version the agent last read, and answers `conflict` with the current one when someone else changed the entry in between: nothing is overwritten by accident.

## History and going back

Each entry keeps its history: every revision, newest first, with who wrote it (a person, or the agent of their token or app, with the client it named), when, its title, what the contracts said, and which one the site shows now.

- **In the admin**, open the entry and its **History** tab. A revision opens beside the latest one, with what changed marked, and **Restore this version** goes back to it.
- **Over MCP**, `list_revisions` lists them, `get_revision` reads the whole Markdown of one, and `restore_revision` goes back to it.

Going back never deletes or rewrites anything: the earlier revision's Markdown is saved again as a new revision, with the check of the version and the contracts of any save, and the history keeps every revision, the one you left included. The restored version is a draft until you publish it, so the site shows what it showed until then. To take back a publication at once, restore the revision the site showed before, then publish.

## Publishing

`publish` makes one revision the live one. The contracts run again in the publish phase, which can see more than a write can: whether the links point at published entries, whether the translations exist.

After that:

- sites that read over the binding or the read API see the new content on their next read;
- the events of the publication go to the site's webhooks and to IndexNow, if it has them (in the admin, under **Site**), through a queue that retries; each event says which [cache tags](/docs/caching/) it invalidates.

An entry with unpublished changes keeps serving its published revision until you publish again. `unpublish` takes it off the sites and keeps its revisions.

## Preview on the site

In the admin, an entry's **Preview on the site** opens its page on your site with its latest revision, a draft included, before anyone publishes it. The link is signed for that one entry and lasts an hour; your site exchanges it for a cookie at once, so it does not stay in the address bar or the history. `@hollware/nuxt`, `@hollware/astro`, `@hollware/react` and `@hollware/vue` (with a server) do the exchange; nothing a previewed page answers is cached. It needs the site's `url` in the admin, under **Site**, and the Worker secret `HOLLWARE_SECRET`, which `hollware deploy` sets.

## Scheduling

`publish` takes `publishAt`, a moment in the future: the entry is published then, by the cron trigger of the Worker, with the contracts run again at that moment.

The end of a publication is scheduled too, for an offer, an event or a notice that ends: `schedule_unpublish` takes the entry and `unpublishAt`, and the cron takes it off the sites within a minute of that time, in the name of whoever scheduled it, if they may still publish. Scheduling again moves the time, `unpublishAt: null` cancels it, and `get_entry` answers it as `unpublishAt`. In the admin, a published entry has **Unpublish at**, beside **Unpublish**.

## Change the URL of an entry

`move_entry` gives an entry another slug, and so another path on the site. It keeps its revisions and its translations, and takes the version you read, like `update_draft`. Moving a published entry takes `content:publish`, since the page moves at once and its pages are purged.

An entry that was ever published keeps its old slug as a **redirect**: a site answers the old path with a 301 to the new one, so links and search engines follow. Moving it back to an old slug drops that redirect. `list_redirects` lists them, newest first, with both paths when the collection has a route. A site reads them with `listRedirects`, or `createHollware().redirectFor(collection, locale, slug)`, and `hollware export --published` writes them to `redirects.json` for a site built from files.

In the admin, an entry has **Change URL**, and **Site** lists the redirects.

## Translations that fall behind

A translation is an entry of a translation group in another locale than the site's default. When its source, the entry of the group in the default locale, changes after the translation was saved, the translation is **outdated**: `list_entries`, `get_entry` and `get_translations` answer `translationOutdated: true`, and the admin marks it and filters by it. Saving the translation again brings it up to date.

## Your Markdown

`get_entry` with `formats: ['markdown']` returns a revision exactly as it went in, byte for byte. Your content is never locked in a format of Hollware's.
