# Publishing Artifacts

> One file in, one URL out. Same name again is a new version.

**URL:** https://inference.sh/docs/artifacts/publishing
**Last updated:** 2026-10-25

---

**One file in, one URL out. Same name again is a new version.**

```bash
belt artifact publish ./deploy-failures.html
```

The file is the page *content*, not a whole document. It is wrapped at publish time in `<!doctype html>`, a `<head>` carrying the charset, viewport, title, favicon, a reset and the inference.sh design tokens, and a `<body>`. Put your own `<style>` and `<script>` at the top of the content.

A complete document is accepted too — if the file starts with `<!doctype>` or `<html>`, it keeps its own `<head>` and only the missing pieces are injected.

---

## Several pages

Publish a folder with an `index.html` (or `index.md`) and the whole folder becomes one artifact:

```bash
belt artifact publish ./site --title "Launch notes"
```

Its other pages, stylesheets, scripts and data (`.html`, `.md`, `.css`, `.js`, `.json`, `.svg`, `.txt`, `.xml`, `.csv`) are served beside the index. Hidden files are left out.

- Link pages with relative links: `pricing`, `pricing.html` and `docs/` all work, and `docs/setup` finds `docs/setup.md`.
- Links stay inside the page, and the address follows: `app.inference.sh/artifacts/<id>/page/pricing` opens that page directly.
- A page can `<link>` its own stylesheet, `<script src>` its own script, and `fetch("data.json")`.
- Publishing again replaces the whole site. Up to 200 files, 16 MiB in all.

---

## Flags

| flag | |
|---|---|
| `--title` | page title; defaults to the file name |
| `--name` | url slug; defaults to the title |
| `--desc` | one-sentence description for the gallery card |
| `--favicon` | one or two emoji, used as the tab icon |
| `--type` | `html` or `markdown`; defaults to the file extension |
| `--label` | a name for this version, e.g. `"draft to legal"` |
| `--id` | update an existing artifact instead of creating one |
| `--capability` | repeatable: `db`, `user`, `assets` |
| `--open` | open it in the browser afterwards |
| `--if-version` | publish only while the artifact is still on that version |
| `--force` | publish over a newer version, discarding it |

Markdown gets GitHub-flavored rendering and a readable default typography — good for a document-shaped page.

---

## Updating in place

Publishing the same name in your namespace, or passing `--id`, appends a version. The URL never changes. Unless a version is [pinned](/docs/artifacts/sharing#versions), the new one becomes the live version and viewers with the page open see it; they are served nothing else. The versions behind it, labels included, are visible to the owner and editors only.

```bash
belt artifact publish ./report.md --id acme/q3-funnel --label "with regions"
```

Identical content is a no-op rather than a new version.

If two people might be publishing, `--if-version` refuses rather than discarding whatever landed in between:

```bash
belt artifact publish ./report.md --id acme/q3-funnel --if-version 7ffy8k1e
```

`--force` publishes anyway. Either way viewers only ever see what is live; the history the check is made against is the editors' to read.

---

## What a page may load

A page has no backend of your own. It can load its own files ([Several pages](#several-pages)); everything else comes from the hosts below.

External resources are restricted by CSP, and failures are silent — a blocked script simply never runs:

- **scripts** only from `cdnjs.cloudflare.com`, `cdn.jsdelivr.net/npm/`, `cdn.tailwindcss.com`, `code.jquery.com`
- **stylesheets** only from `fonts.googleapis.com`, with font files from `fonts.gstatic.com`
- **fetch, XHR and WebSocket** reach only the page's own files

Load libraries as pinned UMD builds, before the inline script that uses them:

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
```

Embed small images as `data:` URIs. For anything sizeable use [assets](/docs/artifacts/capabilities#assets) — a `data:` URI costs about a third more than the bytes it carries, and the source has a 16 MiB ceiling.

---

## Cover

`belt artifact publish --image <url>` sets the gallery card's cover yourself, and a chosen cover is never replaced. Without one, when the platform's server covers are enabled, the API renders the top of each newly published version (light and dark) in the background and uses that as the cover. See [Covers](/docs/api/rest/artifacts#covers).

---

## Theme

The viewer's theme is stamped on the page, and the wrapper defines the inference.sh tokens as HSL triplets. Use them and the page follows the platform in light and dark:

```css
body { background: hsl(var(--background)); color: hsl(var(--foreground)); }
```

Pick one approach: theme tokens only, or a fully self-defined palette that overrides every colour. Mixing the two is what produces a page that looks broken in one mode.
