# zotero-pkg: Debian packages for Zotero, rebuilt within thirty minutes of each release

> zotero-pkg packages the Zotero reference manager for Debian-based systems, rebuilding within thirty minutes of each upstream release, with a nightly beta, a Nix flake and a single install.sh that wires up an apt repository. The interesting design decision is that the packaged builds have their self-update disabled, so the system package manager is the only thing that updates them.

**retorquere/zotero-pkg** — Packaged versions of Zotero and Juris-M for Debian-based systems

- Repository: https://github.com/retorquere/zotero-pkg
- Website: https://zotero.retorque.re/file/apt-package-archive
- Stars: 1,311 · Forks: 40
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/retorquere-zotero-pkg

## What the packages are, and where Zotero puts them

This repository contains packaged releases of Zotero for Debian-based Linux systems and Crostini-enabled chromebooks, and the script used to build them. It also offers the latest nightly zotero-beta.

The primary source for the packages is an apt package archive at zotero.retorque.re/file/apt-package-archive, and there is a mirror at mirror.mwt.me/zotero/deb. The README notes that a mirror was commented out in the source because it was down at the moment, which is the kind of detail that tells you this is a one person operation with real operational realities.

The key property is speed of release. The repository updates to new releases of Zotero within 30 minutes, often faster. Zotero itself ships a tarball and a self-updating application, neither of which fits a Debian package, so somebody has to do the repackaging, and this is that somebody.

What goes into the package is straightforward. The packages include the whole Zotero binaries, as built by the Zotero team themselves, so the packaging does not rebuild the application from source, it repackages the upstream binaries. And the packages provide a system-wide installation into the /usr/lib directory, as opposed to a single-user installation, for example in your HOME directory. They manage both desktop file registration and MimeType registration.

That last point is the substantive difference between this and the tarball install. A system-wide install registers the application with the desktop environment, so it appears in the launcher, and it registers its MimeType, so that opening a .bib or .ris file launches Zotero. The tarball install does none of that, and the README tells you what to do about it: if you have previously used the tarball install, delete ~/.local/share/applications/zotero.desktop.

The primary language in the repository metadata is JavaScript, and the licence in the repository metadata is MIT, though the package.json declares the package itself under ISC. The repository is not archived, the last push was on 2026-10-13, and the only release tag is apt-get from 2021-12-14, so the tag history is not where the versioning information lives. The homepage is zotero.retorque.re/file/apt-package-archive.

## Installing, and what install.sh actually does

The install is a script piped into a shell with sudo:

```
curl -sL https://raw.githubusercontent.com/retorquere/zotero-pkg/master/install.sh | sudo bash
```

and then the normal apt flow:

```
sudo apt update
sudo apt install zotero
```

The wget form is the one given in the Installing Zotero section, and the README notes you can use curl instead of wget by typing the curl variant.

What install.sh actually does is worth reading, and the README is unusually upfront about it. There is a risk to running random scripts from the internet as root. The script is fairly simple though, and the actions can be done by hand fairly easily. In the end it installs either /etc/apt/sources.list.d/zotero.list or /etc/apt/sources.list.d/zotero.sources and the regular apt infrastructure is used from that point on.

So the script adds one repository pointer file, and it asks for sudo permissions to install the pointer to the apt repo and to add the signing key to the keyring. Everything after that is stock apt. That is a much smaller privilege ask than a script that downloads and runs a binary, and the README is giving you the information to decide.

There is a variant of the install for a specific reason. The accepted key format in Debian-based systems seems to have changed a while ago, which means the existing signing verification key you have may no longer be available during install, and re-running the install script will remedy that. So if apt starts complaining about the key, the fix is to run the same script again.

There is also a flag for the newer repository pointer format. To use the new deb822 repo pointer format, add the -m sources flag:

```
curl -sL https://raw.githubusercontent.com/retorquere/zotero-pkg/master/install.sh | sudo bash -s -- -m sources
```

The flag is passed after a double dash, which is the convention for passing arguments to a script being run from stdin, and it selects the .sources file instead of the .list file.

Crostini-capable Chromebooks have their own instructions, on the repository wiki, because the environment is different enough that the same script does not obviously apply.

And uninstalling is symmetric:

```
wget -qO- https://raw.githubusercontent.com/retorquere/zotero-pkg/master/uninstall.sh | sudo bash
sudo apt-get purge zotero
```

The separate uninstall script is a good sign. A pipeline that installs a repository and a pipeline that removes it are two different operations with different failure modes, and separating them means you can remove the repository without touching the package and the other way round.

## Self-update disabled, and why that is the right call here

The single design decision that distinguishes this packaging from the upstream application is a line in the Updating section. The Zotero programs provided by this repository have their self-update facility disabled. Simply rely on your system's package manager to give you update notifications when a new version comes out.

The alternative commands are just:

```
sudo apt update
sudo apt upgrade
```

This is the right call, and the reason is that a self-updating application inside a system package manager is a mess. If the application can rewrite its own files in /usr/lib, then the package manager's idea of what is installed stops matching what is on disk, and the next apt upgrade overwrites files the application has already changed. Worse, the version numbers diverge: the package manager believes it installed 7.0.9 while the application has silently moved to 7.0.10, and there is no way to uninstall or downgrade cleanly. Two update mechanisms on the same files is the classic way to end up with an unremovable application.

So this repository moves the entire update responsibility to apt, and the packaging release cadence of thirty minutes means there is effectively no delay between an upstream release and a package. What you give up is the in-app update notification, and what you get is a system where the whole machine is managed by one tool.

That also explains the beta channel, which is a separate package name. The nightly zotero-beta is installable alongside the regular packages, and the README says you can install them side by side. Two package names rather than one package that changes behaviour, so a beta user can run the beta and the stable at the same time and compare them, which is exactly what a beta channel is for.

The remaining piece is the trust chain. The repository pointer is signed with a key, and the repository carries both zotero-archive-keyring.asc and zotero-archive-keyring.gpg at the top level. The .gpg file is the keyring and the .asc is the exported public key in ASCII form, and the Makefile target that produces the .asc runs gpg with --export -a against that keyring, with --no-default-keyring and --homedir /dev/null so the export cannot pick up anything from the developer's own keyring. That is a careful detail for a file that gets trusted by apt on a user's machine.

## Why the packaging exists at all, and the Crostini case

Zotero is a reference manager, and the reason it needs packaging work at all is that upstream ships a self-contained application rather than a system-integrated one. It is distributed as a tarball you extract and run, with a desktop file you place yourself if you want it to appear in your launcher, and it updates itself by downloading a new build over the old one.

That model is fine on a personal machine and awkward everywhere else. On a managed workstation, on a school machine where the user does not have write access to system directories, or on a Chromebook, a tarball install does not fit. The packaging here addresses three of those cases.

The first is the Debian family, where apt is the expected installation mechanism and a self-updating application in /usr/lib is a maintenance liability. That is the system-wide install into /usr/lib, with the desktop file and the MimeType registration handled.

The second is the update model, which the previous section covers, and which is the reason the packages disable self-update.

The third is Crostini, the Linux container environment on Chromebooks, and it is interesting because it is the case where the upstream model breaks hardest. Crostini is a container, so anything installed into the system directories of the container is ephemeral and depends on how the container is provisioned. The README handles that case by giving it its own instructions on the repository wiki rather than trying to fold it into the standard path, and the fact that a wiki exists for it at all suggests it is a supported but distinct flow.

The repository also carries Juris-M in its history. The description in the repository metadata is Packaged versions of Zotero and Juris-M for Debian-based systems, and the README shows the Juris-M logo and links throughout, with the beta package named jurism-beta. The body text in the README has the Juris-M mentions commented out in the source, which is the shape of a project that supported two applications and has narrowed to one. The package.json description confirms the current focus, Build debian packages for Zotero.

That is worth noting for anyone evaluating the project as a general reference. The pipeline is built around one upstream application with a specific release cadence and a specific update philosophy. The pieces that would generalise, the apt repository plumbing, the keyring handling, the deb822 support and the Nix packaging, are the reusable parts, but the build configuration is specific to Zotero, and the author is a single person, the repository metadata naming Emiliano Heyns as the author of the npm package.

The final piece of the trust picture is the archive URL itself. The packages are served from a personal domain, zotero.retorque.re, with a mirror at mirror.mwt.me, and the apt signing key is committed to the repository in two formats. The README gives the primary source as a link at the top and the mirrors separately, and the commented out mirror entry in the source shows the author disabling one that was down. For a user, the practical question is whether the archive you are pointed at by a script running as root is one you trust, and the answer has to be yours rather than the package manager's.

## The Nix path, and how the packages are built

Beyond apt, the project now also offers experimental Nix packages, and the README is clear that Nix is a prerequisite rather than a bundled tool. If you do not have Nix on your system yet, you need to set it up first, and Nix works on any Linux distribution, Fedora, Ubuntu and others, and on macOS.

There is a binary cache, which is the part that makes Nix usable for a non Nix user. To avoid building Zotero from source, you can use the retorquere cache, which downloads the pre-built binaries directly. If you have Cachix installed:

```
nix profile install nixpkgs#cachix
sudo cachix use retorquere
cachix use retorquere
```

The three commands are the standard Cachix trust dance. The first installs the Cachix client itself from nixpkgs, the second registers the cache as a substituter with sudo so it applies to the whole system, and the third does it for the current user, so the cache is used whether you are in a nix shell or not.

And you can try it without installing anything at all. Run Zotero immediately without a permanent installation, with the files kept in a temporary cache and not touching your system configuration:

```
# Run the Stable version
nix run github:retorquere/zotero-pkg#zotero

# Run the Beta version
nix run github:retorquere/zotero-pkg#zotero-beta
```

That is the entry point to try before committing, and it is a better first experience than piping a root script into bash, which is a fair point given the README's own warning.

For a permanent install there is nix profile add "github:retorquere/zotero-pkg#zotero", which puts it in your profile rather than in the system, and the beta has its own equivalent.

The build side of the repository explains the toolchain. To rebuild this repo you need a deb-based system, the author's own is Ubuntu, and node. The Makefile has three targets. repo runs npm start, which is the build script, and alt runs crystal rebuild-apt.cr, which is an alternative implementation in Crystal, and that is an unusual and interesting thing to find in a JavaScript project. The third target regenerates the exported signing key as described earlier.

The package.json is small and shows the build dependencies. The start script is FORCE_COLOR=3 node index.js, so the build is a Node program with forced colour output. The dependencies are chalk for terminal formatting, dprint for formatting, js-ini and js-yaml for reading configuration, json-stringify-deterministic for reproducible JSON output, and semver for version comparison, which is what handles the decision about which upstream release to package. There is a requirements.txt with xvfbwrapper, which is the headless display wrapper needed to run the application's own UI during packaging, and the top level has config.yml, index.js, staging.js, nix.js and start.py, plus a flake.nix and flake.lock, a zotero-bin.nix and a nix.json.

The test script is dprint fmt *.js, which is a formatting check rather than a test suite, and that reflects what this project is: a packaging pipeline, verified by the fact that the packages install and the applications run.

## Conclusion

zotero-pkg fits a Debian, Ubuntu or Crostini user of Zotero who wants the application to arrive through apt and to be updated by the system rather than by the application, and who is willing to trust a third party repository with a signing key. It is the wrong tool if you want a single user install in your home directory, since the packages are explicitly a system-wide installation into /usr/lib, and the wrong choice if you are on a non Debian system and do not want to install Nix first. Before running install.sh, read the section on what it actually does, because the README itself flags the risk of running a random script from the internet as root, and the script only adds a repository pointer.

## FAQ

### What does the zotero-pkg repository provide?

Packaged releases of Zotero for Debian-based Linux systems and Crostini-enabled chromebooks, plus the script used to build them. The packages contain the whole Zotero binaries as built by the Zotero team, install system-wide into /usr/lib, and handle desktop file and MimeType registration. New upstream releases are packaged within 30 minutes, often faster.

### How do I install Zotero from the apt repository?

Run the install script, then use apt. The script is curl -sL https://raw.githubusercontent.com/retorquere/zotero-pkg/master/install.sh | sudo bash, followed by sudo apt update and sudo apt install zotero. The script adds the repository pointer file and the signing key, and the README notes the actions can be done by hand if you prefer.

### How do I update Zotero when it is installed this way?

The packaged builds have their self-update facility disabled, so the system package manager is the only updater. Run sudo apt update and sudo apt upgrade. A beta build is also available as the separate zotero-beta package, which can be installed alongside the regular one.

### Can I run Zotero from zotero-pkg without installing it system-wide?

Yes, through the experimental Nix packages, which are described as working on any Linux distribution and on macOS once Nix is set up. nix run github:retorquere/zotero-pkg#zotero runs the stable version with the files kept in a temporary cache and without touching your system configuration, and a retorquere binary cache avoids building from source.

## Sources

- [License: MIT](https://github.com/retorquere/zotero-pkg/blob/master/LICENSE)
- [Project website](https://zotero.retorque.re/file/apt-package-archive)
- [README](https://github.com/retorquere/zotero-pkg/blob/master/README.md)
- [Releases](https://github.com/retorquere/zotero-pkg/releases)
- [retorquere/zotero-pkg on GitHub](https://github.com/retorquere/zotero-pkg)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/retorquere-zotero-pkg
