# Deploy Buttons: Let Another Lab Run Your Annotation Study

Source: https://www.potatoannotator.com/blog/deploy-buttons-for-annotation-studies

This tutorial adds a one-click deploy button to an annotation study's git repository, so a collaborator, a student or another lab can run the study in their own cloud account without installing Potato. A replication package usually ships a config and a data file with instructions to install a tool and start a server, and every step of those instructions is a place where a replication can stall. A deploy button replaces them with an account sign-in and one click, and the annotations go to the backup named in the button. The button needs Potato 2.10 or later on your machine and a study whose `config.yaml` and data already live in a git repository.

## Files a deploy button writes

Heroku, Render and AWS CloudFormation can each build a service from files in a repository. Heroku reads `app.json`, Render reads `render.yaml`, and CloudFormation reads a template. `potato deploy button` writes those files for your study and prints the badge to paste into your README. Your own `config.yaml` is never changed. The command writes a copy beside it, `potato.deploy.yaml`, with debug off, sessions persisted and the backup configured, and the generated files point at the copy.

No secrets go into the repository. Heroku and Render generate the session key and the admin key when someone deploys, the AWS template generates them on the instance, and the person deploying supplies the backup credentials at deploy time.

## Choosing a target

The four targets differ in what the person clicking needs:

| `--target` | Files written | What the person clicking needs |
|---|---|---|
| `heroku` | `app.json`, `heroku.yml`, `Dockerfile.potato` | a Heroku account and a backup token |
| `render` | `render.yaml`, `Dockerfile.potato` | a Render account and a backup token |
| `aws` | `potato-lightsail.cfn.yaml` | an AWS account, and your repository must be public |
| `railway` | none, the command prints the steps | a Railway account |

On Heroku, the button runs one Basic dyno at $7 a month, and the dyno's disk is wiped daily. The AWS button creates a Lightsail instance at $12 a month with a disk that persists, which suits a study that will run for weeks. Railway publishes templates from its own dashboard, so for that target the command prints the steps instead of writing files.

## Adding a Heroku button

Run the command from the repository root, naming the study's config and the HuggingFace dataset that will hold the backup:

```bash
potato deploy button studies/pilot/config.yaml --target heroku \
    --backup hf --hf-backup-repo lab/pilot-annotations
```

The Heroku and Render buttons deploy onto disks that do not survive a restart, and nobody pulls the annotations from an AWS button's instance, so all three file-writing targets require `--backup`. Every five minutes the backup copies the annotation output and snapshots of the project databases to the named dataset, and a restarted server restores from it. The backup goes to the dataset you name with `--hf-backup-repo` when you generate the button, and the person deploying supplies a HuggingFace token with write access to it. Every deployment from the button therefore writes to that one dataset. If another lab's annotations should not reach your dataset, have them fork the repository and generate the button again with a dataset of their own.

Before it writes anything, the command checks two files. Heroku and Render build an image from your repository, and `.potato/` (the admin key and deploy secrets), `annotation_output/` and the SQLite databases must stay out of it. If the repository has no `.dockerignore`, the command writes one, and if one exists without those entries, it lists them. It also lists any of those paths that `git check-ignore` does not report as ignored, since a button deploys whatever you pushed.

Commit the generated files and push:

```bash
git add app.json heroku.yml Dockerfile.potato .dockerignore studies/pilot/potato.deploy.yaml
git commit -m "Add a Deploy to Heroku button"
git push
```

Paste the badge the command printed into your README. A visitor who clicks it signs in to Heroku, enters the backup token, and gets the study running at an address Heroku assigns.

## Adding an AWS Launch Stack button

CloudFormation reads templates only from S3, so the AWS button takes one more step. Generate the template, upload it to a bucket you own, then generate the button again with the template's URL:

```bash
potato deploy button config.yaml --target aws --backup hf --hf-backup-repo lab/r
aws s3 cp potato-lightsail.cfn.yaml s3://my-bucket/ --acl public-read
potato deploy button config.yaml --target aws --backup hf --hf-backup-repo lab/r \
    --template-url https://my-bucket.s3.amazonaws.com/potato-lightsail.cfn.yaml --force
```

The stack creates a Lightsail instance and a static IP. The instance clones your public repository, generates its secrets, and starts Potato with a certificate for the static IP. The stack's `URL` output is the address to give annotators, ready a few minutes after the stack completes. The admin key stays on the instance, and the person who deployed reads it from Lightsail's browser SSH with `sudo grep ADMIN /opt/potato/potato.env`.

## Pinning the Potato version and the data

A replication should run the same Potato version as the original. From 2.11, the button pins the image to the Potato version that generated it. Potato 2.10 writes the `latest` tag instead, so a deploy months later runs whatever Potato is current then, and a fix to agreement or export in the meantime can change the numbers the replication reports. On 2.10, pin the image with `--image` when you generate the button, for example `--image ghcr.io/davidjurgens/potato:2.10.3`. Pin the data the same way, by committing it with the config rather than downloading it at start.

`--dry-run` prints every file without writing anything. From 2.10.3, a dry run without `--hf-backup-repo` uses a placeholder dataset name instead of asking HuggingFace who owns the token, so you can check what a button would do without credentials. Existing files are replaced only with `--force`. [Running Potato Locally or in the Cloud](/docs/deployment/quick-deploy#deploy-buttons-for-other-peoples-accounts) covers the button alongside the other deployment targets, and the [deploy buttons documentation](https://github.com/davidjurgens/potato/blob/master/docs/deployment/deploy-buttons.md) lists every option.
