Deploy Buttons: Let Another Lab Run Your Annotation Study
potato deploy button adds a Deploy to Heroku, Render or AWS Launch Stack button to a study's repository, so collaborators run it in their own accounts.
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 each deployment backs up its annotations to storage the person deploying names. This tutorial describes Potato 2.12.0, the first release in which each deployer names their own backup, so generate buttons with 2.12.0 or later. You also need 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 dataset or bucket for the backup |
render | render.yaml, Dockerfile.potato | a Render account, and a dataset or bucket for the backup |
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. A Railway template copies your own deployment, backup storage included, so everyone who deploys it would share your dataset, and the printed steps warn about this.
Adding a Heroku button
Run the command from the repository root, naming the study's config and the kind of backup:
potato deploy button studies/pilot/config.yaml --target heroku --backup hfThe 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 backup storage, and a restarted server restores from it. The person deploying names that storage when they click the button: POTATO_BACKUP_HF_REPO and HF_TOKEN for a HuggingFace dataset, or POTATO_BACKUP_S3_BUCKET with the bucket's keys for S3. Heroku and Render ask for these with no default, and the AWS template takes them as required stack parameters, so each deployment backs up to its own storage. button ignores --hf-backup-repo, --hf-token, --s3-bucket, --s3-region and --s3-endpoint, and says so.
A button generated with Potato 2.11.1 or earlier wrote your dataset into potato.deploy.yaml with restore at startup turned on. A deployer without write access to it got failing backups, one with write access sent their annotations to your dataset, and a new deployment could restore your annotators. Regenerate such a button with 2.12.0 and --force, then commit the files and push.
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:
git add app.json heroku.yml Dockerfile.potato .dockerignore studies/pilot/potato.deploy.yaml
git commit -m "Add a Deploy to Heroku button"
git pushPaste the badge the command printed into your README. A visitor who clicks it signs in to Heroku, names their own backup dataset and enters a token for it, 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:
potato deploy button config.yaml --target aws --backup hf
aws s3 cp potato-lightsail.cfn.yaml s3://my-bucket/ --acl public-read
potato deploy button config.yaml --target aws --backup hf \
--template-url https://my-bucket.s3.amazonaws.com/potato-lightsail.cfn.yaml --forceThe 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, so you can check what a button would do before committing it. Existing files are replaced only with --force. Running Potato Locally or in the Cloud covers the button alongside the other deployment targets, and the deploy buttons documentation lists every option.