Self-hosted service
quay/quay avatar
quay/quay

Project Quay: a self-hosted container registry with geo-replication and Clair scanning

Build, Store, and Distribute your Applications and Containers

2,824 stars389 forksPythonApache-2.0

At a glance

What is it?
Project Quay is the Apache-2.0 registry behind Quay.io, built on Flask, PostgreSQL and Redis. It suits teams that need LDAP or OIDC login, replicated blob storage and their own vulnerability scanning rather than a hosted registry.
Who is it for?
Adopt Project Quay if you need an in-house registry with LDAP, OIDC or Keystone login, per-team ACLs and replication across regions or storage backends, and you are willing to run PostgreSQL, Redis and the worker processes that go with it. Do not adopt it if you only need somewhere to push a few private images; a single-process registry or a hosted service costs far less to operate.
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 6 days 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 September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Project Quay solves, and who ends up running it

A container registry looks like a solved problem until an organisation needs to know who pushed which image, from which CI job, and whether that image contains a known CVE. Project Quay is aimed at that second stage. The README describes it as software that builds, stores and distributes container images, and the feature list is the giveaway: ACLs, team management and auditability logs sit alongside authentication through LDAP, Keystone, OIDC, Google and GitHub. Those are the concerns of a platform team inside a company, not of a solo developer who wants a private place to push an image.

The same list points at the second audience: teams with a footprint in more than one place. Geo-replicated storage is offered through local filesystems, S3, GCS, Swift, Ceph and ODF. If you already run Ceph or OpenStack Swift and want images to live there rather than in a vendor's bucket, the registry has to speak those backends natively. Project Quay does. A registry that only understands S3 will not.

The third piece is scanning. The README lists security vulnerability analysis via Clair, the companion project in the same GitHub organisation. Clair is a separate service, which matters for deployment: the registry does not scan images by itself. The repository acknowledges this by shipping a make target that brings Clair up alongside the local stack.

Who is this not for? Anyone who wants a registry with no database, no Redis and no background workers. Project Quay is a Flask application with a PostgreSQL schema and async job processing, and that shape is visible in the repository map before you read a single line of code.

How the pieces fit: Flask endpoints, PostgreSQL, Redis and workers

The repository map in the README is the clearest description of the architecture. Docker, Podman, the UI and API clients all talk to a Flask application. That application splits into two endpoint families: endpoints/api serves the Swagger-compliant HTTP API, and endpoints/v2 serves registry protocol traffic, meaning the Docker Registry Protocol v2 and the OCI distribution spec. Both families read and write through data/model and data/registry_model, which is the layer that touches PostgreSQL and Redis.

Blob traffic does not go through the database. The map shows endpoints/v2 reaching the storage backends directly, which is what you would expect: image layers are large and should not be proxied through a relational store. Metadata, permissions and repository state go to PostgreSQL; Redis handles caching and the coordination the web processes need. Workers run async jobs against both the data layer and storage, which is where builds, garbage collection and similar long-running operations live.

Two details in the repository layout are worth noting because they constrain how you operate it. First, data/database.py is described as the schema source of truth, and alembic.ini at the top level means schema changes ship as Alembic migrations. Upgrading Quay is therefore a database migration event, not just an image swap. Second, config-tool/ exists to validate configuration, and the README points at it explicitly. That is a sensible response to a product whose behaviour is driven by a large config file, but it also tells you the configuration surface is wide enough to need its own validator.

The README also warns that the master branch may be in an unstable or even broken state during development and directs users to releases instead. Treat that as a deployment instruction, not a formality.

Running the local stack and pushing your first image

The README's getting started guide covers developing or deploying Quay, and the repository includes a docker-compose.yaml plus Makefile targets for a local environment. The documented shortcut is a single make target, which brings up the stack and leaves the legacy Angular UI listening on port 8080.

bash
make local-dev-up

If you want vulnerability scanning in that local environment, the README gives a second target that also starts Clair. Use it when you need to see scan results rather than only push and pull images.

bash
make local-dev-up-with-clair

The frontend has a split worth knowing about before you go looking for the interface. The legacy Angular UI under static/ is what make local-dev-up serves on http://localhost:8080. The newer React UI under web/ runs separately on http://localhost:9000, and the README's instructions are to install its dependencies and start it after the backend is up.

bash
cd web
npm install
npm start

One operational detail from the README saves time during backend work: if code changes are not reflected in the running stack, restart the Quay container by name.

bash
podman restart quay-quay

For tests, the README documents running a single test file with the environment variable set and PYTHONPATH pointed at the repository root, plus aggregate targets for unit, registry and type tests. The registry test target is the one to run after touching endpoints/v2, since that is the code path every Docker and Podman client depends on.

bash
TEST=true PYTHONPATH="." pytest path/to/test.py -v

Where Project Quay is the wrong choice

The operational surface is the first real cost. A working deployment needs PostgreSQL, Redis, the Flask web processes and the worker processes, plus whatever storage backend you choose. The local development stack hides this behind one make target, but production does not. If your requirement is a private registry for a handful of images, that is four moving parts where a single binary would do, and every one of them is a thing that can page you at night.

The configuration surface is the second. The presence of config-tool/ to validate configuration is evidence that getting the config wrong is a realistic failure mode, and the README does not document rollback for a bad configuration or a failed migration. That absence matters more than it looks: Alembic migrations run forward, and the README says nothing about reversing them. Plan a database backup before an upgrade rather than assuming you can step back.

Third, the README explicitly warns that master may be unstable or broken. Anyone who clones the default branch and deploys it is outside the supported path. The releases page is the supported source, and the project maintains parallel release lines, with v3.12.22, v3.10.26 and v3.9.26 all published within September 2026. Running an older line means tracking backports rather than the mainline.

Finally, scanning is not built in. Vulnerability analysis comes via Clair, a separate service you deploy and keep running. If you expected the registry to report CVEs out of the box, you will be running a second system before you get that answer. The README also does not describe how scan results are refreshed or how the registry behaves when Clair is unavailable, so that failure mode has to be established by reading the code or testing it yourself.

How it differs from the reference registry and from hosted services

The obvious comparison is the reference Docker registry, which implements the same protocol surface and stores blobs in a configured backend. The difference is what sits around the protocol. The reference registry has no user model, no teams and no ACLs beyond a basic token arrangement; authentication is delegated to a separate token service you write. Project Quay ships the identity layer: LDAP, Keystone, OIDC, Google and GitHub are supported directly, and team management and audit logs are part of the product. The reference registry is the right tool when a token service already exists in your infrastructure; Project Quay is the right tool when you would otherwise be building one.

The second comparison is hosted registries, including Quay.io itself. The README opens by pointing at a live instance hosted at Quay.io, which is the same software operated for you. Choosing the hosted service removes PostgreSQL, Redis, workers, migrations and Clair from your plate. Choosing to self-host buys control over where blobs live (your Ceph cluster, your Swift deployment, your S3 bucket), control over identity integration, and the ability to keep image metadata inside your network. That is a real trade, and it is the only reason to take on the operational cost.

A third point of difference is the build integration. The README lists continuous integration with GitHub, Bitbucket, GitLab and plain git. That is a feature the reference registry does not attempt, and it is what makes the repository named quay-builder, listed among the related repositories, meaningful. If you only need to store images that a CI system already built elsewhere, you are paying for a capability you will not use.

Maintenance, upgrades and the licence

The repository is not archived, and the last push was on 2026-09-24. Releases are frequent and maintained on multiple lines at once: v3.12.22 on 2026-09-11, v3.10.26 on 2026-09-09 and v3.9.26 on 2026-09-09. Three parallel lines means security fixes are backported rather than landing only on the newest version, which is good news if you cannot upgrade quickly, and a maintenance burden if you are the one running the older line and watching for backports.

The upgrade cost is dominated by the database. With alembic.ini at the top level and data/database.py named as the schema source of truth, a version upgrade includes schema migrations that must run before the new code serves traffic. The README does not document a rollback procedure, so the practical control is a tested backup taken immediately before the upgrade. Configuration is the other half: config-tool/ exists to validate it, and using that tool before restarting is cheaper than debugging a web process that refuses to start.

On licensing, Project Quay is under the Apache 2.0 license, and the README directs readers to the LICENSE file. Two things in the repository deserve a look before you assume the whole product is uniformly licensed. The root package.json declares "license": "UNLICENSED" and "private": true, which describes the frontend build rather than the project as a whole. Separately, the README mentions Red Hat Quay documentation and a Quay Operator, which are Red Hat products distinct from the upstream project. If your organisation has rules about which components you may ship, read the LICENSE file and the dependency licences in requirements.txt rather than relying on the top-level statement. This is not legal advice; it is a pointer to where the question is answered.

Editorial conclusion

Adopt Project Quay if you need an in-house registry with LDAP, OIDC or Keystone login, per-team ACLs and replication across regions or storage backends, and you are willing to run PostgreSQL, Redis and the worker processes that go with it. Do not adopt it if you only need somewhere to push a few private images; a single-process registry or a hosted service costs far less to operate. Before committing, verify that a release tag rather than master is what you will build from, that your storage backend appears in the supported list, and that your database version is covered by the Alembic migrations in the repository.

Frequently asked questions

What is Project Quay used for?

It builds, stores and distributes container images, serving the Docker Registry Protocol v2 and OCI spec v1.1 through a Flask application backed by PostgreSQL and Redis. Around that it adds team management, ACLs, audit logs and vulnerability analysis via Clair.

How do I get Project Quay running locally?

The README documents make local-dev-up, which starts the stack and serves the legacy Angular UI on http://localhost:8080. A second target, make local-dev-up-with-clair, also starts Clair for vulnerability scanning.

Does Project Quay scan images for vulnerabilities by itself?

No. The README lists security vulnerability analysis via Clair, a separate project, so scanning requires deploying and running Clair alongside the registry.

Which storage backends can Project Quay use?

The README lists geo-replicated storage provided by local filesystems, S3, GCS, Swift, Ceph and ODF. It does not document a fallback behaviour for those backends.

Can I deploy the master branch of Project Quay?

The README warns that master may be in an unstable or even broken state during development and directs users to the releases page instead. Deployment should follow a release tag.

What licence is Project Quay under?

The README states Project Quay is under the Apache 2.0 license and points to the LICENSE file. Note that the root package.json declares the frontend build as UNLICENSED and private.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. quay/quay on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/quay-quay.svg)](https://hysenlabs.com/projects/quay-quay)