Project Quay ships two front ends and one build definition for the old one
Build, Store, and Distribute your Applications and Containers
At a glance
- What is it?
- A container registry written in Python on Flask, with PostgreSQL and Redis behind it. The default branch warns you off the default branch, the root package.json still builds the legacy Angular UI, and setup.py carries a version number that matches no current release.
- Who is it for?
- Project Quay suits organisations that need a self-hosted registry with ACLs, audit logs and geo-replicated storage across S3, GCS, Swift, Ceph or a local filesystem, and that can accept depending on NATS-adjacent infrastructure in the same shape. Three things to settle first.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- quay/quay2,846 ★ · +19
| Repository | 2026-10-04 | 2026-11-14 |
|---|---|---|
| quay/quay | 2.8k | 2.8k |
19 Stars in the last 41 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The default branch carries a warning against the default branch
The first thing the README says after the title is a caution: the master branch may be in an unstable or even broken state during development, and releases should be used instead. That branch is also the repository default, so a plain clone lands you on the branch the project tells you not to trust. The warning is not boilerplate either, since the release history shows work continuing after it: tags v3.12.22, v3.14.9 and v3.16.6 were all published in September 2026, and the newest of them is dated later than the repository's own last push. For anyone integrating against Quay, that means the version you get from a clone and the version you get from a tag can differ in behaviour, and only the tag carries a promise of stability.
Two front ends exist, and only the legacy one has a root build
The local development notes describe two user interfaces running side by side. A legacy Angular UI in static/ is started by the local development target and served on port 8080, while a new React UI in web/ runs separately on port 9000 and has to be started by hand after the backend stack is up. The build definitions do not match that split. Everything in the root package.json serves the legacy side: webpack writing into static/build, karma for browser tests, tslint as the linter, a jasmine configuration pointing at static/test/jasmine.json, and a spec glob under static/js. The React side has no entry in the root manifest at all.
cd web
npm install
npm startThe root manifest also pins the legacy stack to angular, angular-route and angular-sanitize all at 1.6.4, with jquery at 3.5 and rxjs at 5.5.7, a consistent generation of libraries from before the AngularJS rewrite.
Protractor still drives the end to end tests
The end to end script invokes ts-node against a Protractor configuration file under static/test, and Protractor drives Selenium, which no longer receives updates. That target therefore exercises the Angular interface, not the React one, so the newer front end has no end to end coverage in this repository at all. Around it sits a wider set of quality gates, one per language and one per concern: .flake8 for Python, .golangci.yml for the Go components, a pre-commit configuration, gitlint for commit messages, a gitleaks configuration for secret scanning, and a git-blame-ignore-revs file that keeps formatting commits out of blame. The Python formatting target is black at a line length of 100, and pylint has five categories disabled including missing-docstring and too-many-lines. The dev shortcuts are a single list:
make local-dev-up
make local-dev-up-with-clair
TEST=true PYTHONPATH="." pytest path/to/test.py -v
make unit-test
make registry-test
make types-testThe root package.json declares UNLICENSED under an Apache LICENSE file
The repository ships a LICENSE file and the README states that Project Quay is under the Apache 2.0 license. The root package.json says something different: its license field reads UNLICENSED, alongside private set to true and a version of 1.0.0. Nothing is broken by this, because the manifest describes the private JavaScript workspace rather than the distributed project, but it does mean a tool that reads licence fields from manifests will report no licence for the tree that owns the legacy UI build. The same pattern shows up in the version fields. The manifest says 1.0.0 and the Python packaging says 3.13, while the tags being published are on the 3.12, 3.14 and 3.16 lines. Three different version answers live in the repository at once.
setup.py filters out the one dependency pinned to a commit
The Python packaging is still the setuptools path: pyproject.toml carries only tool configuration, with sections for black, isort, pylint, coverage and pyright, and no build-system or project table anywhere. setup.py reads requirements.txt at build time and assembles install_requires itself, skipping lines that begin with a hash, lines that begin with git+, lines containing an at sign, and setuptools or wheel themselves. The filter meant for path and reference style requirements also catches the one dependency that is genuinely pinned to a commit. The requirement line for aniso8601 is a direct reference carrying a git URL and a full commit hash, so it contains an at sign and is dropped. The package will build and install without it. The pinned versions around it are a similar mix of eras, from elasticsearch at 7.6.0 alongside cryptography at 46 and pillow at 12.
Three release lines were patched inside a single month
Three tags in September 2026 sit on three different minor lines: v3.12.22 on the 11th, v3.14.9 on the 25th, and v3.16.6 on the 30th. That is a maintenance policy rather than an accident, since a project shipping one line only would have produced a single sequence, and it means an operator has to choose which line to run and then keep choosing as patches arrive. The changelog is generated rather than handwritten, with a .chglog directory and a CHANGELOG.md at the root. One date is worth noting carefully: v3.16.6 was published on 2026-09-30, which is later than the repository's recorded last push of 2026-09-24. The release therefore cannot have come from the branch state the metadata describes, so anything derived from that push predates the newest tag you can install.
Agent configuration is the widest part of the tree
Alongside the code sits a wide set of files aimed at automated tooling. There is a .claude directory and a .agents directory, three separate instruction documents in AGENTS.md, CLAUDE.md and GEMINI.md, an agent_docs directory, an .mcp.json for Model Context Protocol servers, and a .coderabbit.yaml configuring an automated code review bot. Whether a contributor needs all of them is not decided anywhere in the documentation, so the practical effect is duplication with no stated owner, and a change to build or test instructions has to be mirrored across several files to stay consistent. Where the guidance does live is also unusual. The parts of the README that explain how to work on the code sit in a section called the Contextification Addendum, placed after the License section rather than before it, and they hold the mermaid repository map, the key paths and the development shortcuts. Everything above that section is a feature list and a set of outbound links. Those links point outward rather than inward: the documentation link goes to Red Hat's product documentation on access.redhat.com, and one of the suggestions is to explore the live instance at quay.io instead of installing anything. The governance side is more settled: OWNERS names maintainers, GOVERNANCE.md exists, CONTRIBUTING.md covers contributions, and SECURITY.md is the stated route for reporting a vulnerability.
The schema of record is a Python module while migrations run through Alembic
The repository map calls data/database.py the schema source of truth, and separately the root carries alembic.ini and an active_migration.py, so the model definitions and the migration chain are two artefacts that have to agree. The same map routes the data layer at both PostgreSQL and Redis, which puts Redis in the request path for the data model rather than only in front of it, and it routes registry traffic to endpoints/v2 while the general API goes to endpoints/api. Storage writes go straight to the configured backend from both the registry path and the workers, and config-tool/ is what validates configuration. Packaging reflects a project with several delivery targets: four Dockerfiles, for the main build, a downstream build, a mirror build and that mirror's dockerignore, alongside two compose files, one of them docker-compose.static for the legacy interface. Breadth is the other theme. Five authentication providers are offered, LDAP, Keystone, OIDC, Google and GitHub, four CI systems integrate, and six storage backends are listed, local filesystems, S3, GCS, Swift, Ceph and ODF. The OCI support claim is the one to check before you rely on it, since the specification link behind it points at v1.1.0-rc1, a release candidate rather than a final tag.
Editorial conclusion
Project Quay suits organisations that need a self-hosted registry with ACLs, audit logs and geo-replicated storage across S3, GCS, Swift, Ceph or a local filesystem, and that can accept depending on NATS-adjacent infrastructure in the same shape. Three things to settle first. Pin a release tag rather than tracking master, because the project's own warning says that branch can be broken and the default branch is master. Decide which front end you are actually building, since the Angular UI in static/ has a complete root toolchain while the React UI in web/ has none and must be installed from inside its own directory. And treat the package version with suspicion: setup.py hardcodes 3.13 while tags are landing on three separate lines at once, and its dependency filter silently drops the one requirement pinned to a git commit.
Frequently asked questions
What is Project Quay?
A container registry that builds, stores and distributes images, implemented as a Flask application in Python. It speaks Docker Registry Protocol v2, Docker manifest schema v2.1 and v2.2, and OCI spec v1.1, and it adds ACLs, team management and audit logs. The project is under the Apache 2.0 license.
Why does Quay warn against using its master branch?
The README states that the master branch may be in an unstable or even broken state during development, and directs users to releases for stable software. Master is also the default branch, so a clone gives you the branch the project warns against.
Which storage backends does Quay support?
Local filesystems, S3, GCS, Swift, Ceph and ODF, described as geo-replicated storage. Authentication separately comes from LDAP, Keystone, OIDC, Google and GitHub.
Where are Quay bugs reported?
In a Red Hat JIRA project rather than in GitHub issues. Security problems go through SECURITY.md instead, and the community also has a mailing list, an IRC channel on libera.chat, and a meeting on the first Wednesday of every month at 11:00 AM EST.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/quay-quay)Star history chart for your README
[](https://hysenlabs.com/projects/quay-quay)Was this useful?