Examples are realistic demonstrations of the package for the people who will use it. They are where most new visitors land, and for many they are the first Roc code written against the package that they read. This chapter covers what an example is for, and how the same example is kept correct in two places: the repository, and each release.

Risks and controls for example identity§

Examples that pass in the working tree can fail after packaging because files are omitted, dependency URLs are rewritten incorrectly, or a warm cache hides which bundle was fetched. Test the consumer-facing archive as an artifact. Stage the declared files, verify that intended dependency substitutions are the only changes, and run the archive against candidate bundles with an empty package cache. Inspect and reject unsafe archive members before extraction. These checks establish the tested archive’s behavior for its recorded cases; they do not make the cases representative of every product feature.

What an example is for§

The audience of an example is a user of the package who is probably not familiar with it. It is not a contributor.

An example is not a test, a benchmark or a fixture. Those have their own directories and their own standards. Code that exists to cover an edge case, to measure something, or to feed another tool does not belong under examples/, however convenient it is to put it there.

Manage examples with the care their position deserves:

Why examples live in two places§

The repository and its releases are rarely in step. Pull requests land continuously; releases happen now and then. At most commits the package in the repository is ahead of the last release.

An example in the repository must work with the package at that same commit, so it may use an API that no release has yet. A user reading it beside the latest release could copy code that does not compile for them. An example published with a release has the opposite property: it works with that release and will never change.

One set of files cannot be both. The repository therefore keeps examples that follow the working tree, and each release publishes a frozen copy of them that names that release.

Repository examples test the working tree§

Every example names the package by relative path, as described in Roc applications in the repository. A platform’s examples name it the same way, pf: platform "../../platform/main.roc", and run against the host outputs the repository built under platform/. A pull request that changes the package and breaks an example fails on that pull request.

Committed examples are never rewritten after a release. No release follow-up pull request exists, and the default branch never names its own release URL.

Record expected output§

An example that only compiles proves little. Record what each example prints, and compare it on every run. Examples are run by the same driver as the integration tests; see Integration tests.

The examples archive§

Each release attaches an examples archive named <name>-examples-<version>.zip, where <name> is the repository, or the package when the repository publishes several. It contains:

An example is a file examples/<name>.roc, which depends on the package as ../package/main.roc, or a directory examples/<name>/ whose main.roc depends on it as ../../package/main.roc and whose other files travel with it. A .roc file under examples/ without an app header is a module the examples share. An example names at most one platform; one that names none runs on the compiler’s default platform. Each case runs in its example’s own directory, as a reader would run it, so an example reads a sibling data file by relative path; the working tree’s examples run in a scratch copy, so an example that writes files beside itself leaves the tree as it was. Every file Git tracks under examples/ is archived, so a build output that is not committed is never published.

Publish the versioned spec.json and ZIP layout in Publish the suite contract so that the same immutable archive is executable by the central nightly runner.

Nothing else in an example changes. The archived examples differ from the repository’s at the tested commit only in the package dependency, and the check script verifies that.

The one line that differs between the repository and the archive
 app [main!] {
 	cli: platform "https://github.com/roc-lang/basic-cli/releases/download/<version>/<hash>.tar.zst",
-	ansi: "../package/main.roc",
+	ansi: "https://github.com/<owner>/roc-ansi/releases/download/<tag>/<hash>.tar.zst",
 }

A user who wants a starter downloads the archive for the release they are installing. The archive is also the fixed input to nightly compatibility, which is why it carries its own expected output: the default branch’s specification describes the default branch, not the release.

Examples of expensive work, such as fuzzing or benchmarking, expose a small, bounded mode suitable for routine checks. Archive cases use that mode to verify the published API and executable behavior; they do not launch sustained searches or produce performance comparisons. Keep campaigns in their own scheduled workflow, outside both PR dry runs and the shared published-release compatibility verdict.

Build and test the exact archive§

The archive that is tested is the archive that is published. Nothing is rebuilt between the test and the upload.

  1. Build the bundle from the tested commit with roc bundle. Its filename is its content hash and the release tag is the version being released, so the final URL, .../releases/download/<tag>/<hash>.tar.zst, is known before anything is published. A release with several bundles puts a package name before the hash; see Several bundles in one release.

  2. Build the archive with that real release URL in every example.

  3. Serve the bundle from a loopback address.

  4. Run the archived examples with --replace-dep <release URL> <loopback URL>, which roc check, roc test and roc build accept. The files are unchanged; only the download location differs for the duration of the test.

  5. Compare the output with the archived specification.

  6. Publish the same bundle and the same archive.

Run the test with an empty Roc package cache, so that the bundle is fetched and verified and not found from an earlier run.

Dry runs§

A pull request runs the release steps with a placeholder version and publishes nothing. Roc rejects 0.0.0 in a package URL, so the placeholder is 0.0.1-dryrun.

An archive is never reformatted§

An archive is immutable, so it is checked, tested, built and run, and never passed to roc fmt. A later formatter change would fail the nightly check for a reason that no patch release can fix.