# Publishing a Notebook

Publishing puts a notebook at its own web address, where anybody can open it in a browser with nothing installed. `marimo export html-wasm` turns the notebook into a folder of web files. GitHub Pages serves that folder from your course repository at no cost, and the notebook runs in the visitor's browser.

The steps use Mini Project 1, in a folder named `mp1`. For another project, use that project's folder name wherever `mp1` appears.

## Where the files go

```
<course-code>/
├── docs/
│   ├── .nojekyll          an empty file, made once
│   └── mp1/               the export, which you never edit by hand
└── projects/
    └── mp1/
        ├── <your-notebook>.py
        └── public/        the data file your notebook reads
```

GitHub Pages publishes either the top of a repository or a folder named `docs`. Every notebook you publish needs its own folder inside `docs`.

## 1. Put the data in `public`

A published notebook can read only the files published with it. The export copies the folder named `public` that sits beside the notebook, so the file your notebook reads has to go in `projects/mp1/public/`.

Build the path to it with `mo.notebook_location()`, which finds that folder on your machine and on the published page:

```python
df = pl.read_csv(str(mo.notebook_location() / "public" / "countries.csv"))
```

A path written any other way, such as `"public/countries.csv"` on its own, fails on the published page with `FileNotFoundError`.

Write the file name with the capitals it has in `public`. On your computer `Countries.csv` also opens `countries.csv`, and on the published page it does not.

If your notebook pulls from an API, save what it pulled as a file in `public/`, and have the notebook you publish read that file.

## 2. Export

In the VS Code terminal, in the root folder of your course repository, run:

```
uv run marimo export html-wasm projects/mp1/<your-notebook>.py -o docs/mp1
```

Replace `<your-notebook>`, angle brackets included, with your notebook's name.

Run the same line again after every change to the notebook. The published page changes only when you export and push again.

## 3. Make `docs/.nojekyll`

Do this once per repository. In the VS Code file list, right-click `docs`, choose **New File**, name it `.nojekyll`, and save it empty.

Without it, GitHub leaves out every file whose name starts with an underscore. The export contains several, and the page never finishes loading. GitHub looks for `.nojekyll` directly in `docs`, so the copy the export puts inside `docs/mp1/` is not enough.

## 4. Commit and push

In GitHub Desktop, the export appears as several hundred new files. Commit them together with the data file and `.nojekyll`:

1. Summary: `publish mp1`
2. **Commit to main**
3. **Push origin**

## 5. Turn on GitHub Pages

Do this once per repository.

1. In GitHub Desktop, choose **Repository → View on GitHub**
2. Click **Settings**, then **Pages** in the left column
3. Under **Build and deployment**, set **Source** to **Deploy from a branch**
4. Set the branch to `main` and the folder to `/docs`, then click **Save**

## Your address

```
https://<your-github-username>.github.io/<course-code>/mp1/
```

The **Pages** settings page gives the address without `mp1/` on the end. That shorter address shows a 404 because there is no `index.html` directly in `docs`, so add the folder name. GitHub Pages treats `MP1` and `mp1` as different folders, so match the capitals in `docs`.

A project in a repository of its own follows the same steps, with that repository's name in place of `<course-code>`.

## Check that it is live

1. Wait up to 10 minutes after you push.
2. Open the address in a private browser window.
3. Wait for the first output. The browser loads Python before any cell runs, so it takes a while.
4. Compare the numbers on the page with the ones in your notebook on your machine.

If the page still shows an earlier version after a push, wait 10 minutes and reload.

## Limits

**Anybody can read what you publish.** The page contains the notebook's code, and anybody can download the files in `public/`. Never put an API key in a notebook you publish, and publish only data you are free to share.

**No file over 100 MB.** GitHub warns about a file over 50 MB and refuses to push one over 100 MB, so a larger dataset cannot be published this way.

## When it does not work

- **The address shows a 404.** Check that `mp1/` is on the end of the address, that the Pages folder is `/docs`, and that 10 minutes have passed since the push.
- **The page never finishes loading.** `docs/.nojekyll` is missing. Make it as in step 3, then commit and push.
- **A cell shows `FileNotFoundError`.** The file is not in `projects/mp1/public/`, or the notebook reads it without `mo.notebook_location()`. Fix it, export again, and push.
