Open-source project
mozilla/addons-server avatar
mozilla/addons-server

addons-server: the Django application behind addons.mozilla.org

🕶 addons.mozilla.org Django app and API 🎉

905 stars562 forksPythonBSD-3-Clause

At a glance

What is it?
addons-server is the Django project and API that serves addons.mozilla.org, and it is a large, opinionated web application rather than a reusable library. Its value to an outside engineer is as a reference implementation of an extension marketplace, and its cost is a service stack with MySQL, Redis, RabbitMQ, Memcached and Elasticsearch that has to be assembled before anything runs.
Who is it for?
addons-server fits a team that wants to study or fork a working extension marketplace, and an organisation that already runs Django and can absorb a service stack of MySQL, RabbitMQ, Redis, Memcached and Elasticsearch.
Can I use it commercially?
Yes. BSD-3-Clause 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 received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

This is a production web application, not a component

The repository describes itself as the addons.mozilla.org Django app and API, and the README invites people to visit the web page of the current project hosted on addons.mozilla.org. The rest of the file is about how to work on it, not about what it does for developers.

That framing matters for anyone evaluating it. This is the code behind a live, public service that people install browser extensions from, not a library you drop into an application. The classification in the project metadata says so explicitly, with a development status of Production/Stable, an intended audience of end users on the desktop, an operating system of POSIX, and a topic of browsers and the web.

The licence situation has a wrinkle that is worth catching early. The repository licence field reads BSD-3-Clause, and there is a LICENSE file at the root, but the packaging metadata in pyproject.toml classifies the distribution under the Mozilla Public License. Both are permissive, so the practical answer for most organisations is the same, but the two statements are not identical and a compliance check that reads one source and not the other will produce a confusing result. The distribution name is olympia, version 0.1.0, authored by The Mozilla Team, with an [email protected] contact address, and the source lives under a src directory with a package_dir pointing there.

The project is also openly inviting contributions. The README asks for help, points at a Matrix channel at #amo:mozilla.org for questions, and lists a separate repository at github.com/mozilla/addons as the place to report bugs, which is a different repository from the one holding the server code.

The compose file is the real architecture diagram

The docker-compose.yml is truncated in the documentation, but what is visible describes the whole service topology, and it is worth reading as the architecture rather than as configuration.

The environment block lists the backing services by their URLs. There is a Celery broker on RabbitMQ at amqp://olympia:olympia@rabbitmq/olympia and a Celery result backend on Redis at redis://redis:6379/1. The database is MySQL, addressed as mysql://root:@mysqld/olympia, and the application also points at Elasticsearch on port 9200 and Memcached on port 11211.

So the shape is: a Django web application, an asynchronous task queue with a Redis result store, a relational database, a search index, and an in-memory cache. That is a normal architecture for a marketplace of this kind, and it is also the reason the project is not quick to run.

The compose file shows a service named static that publishes port 5173 and runs make run_vite, which is the front end dev server. That is the Vite development server, and the package.json confirms the front end toolchain: Vite for the dev and build scripts, Vitest for the tests, with an engines requirement of Node 18.18 or newer and the package marked as an ES module project. The static service also mounts the working directory into the container and a separate deps directory, which is the pattern for letting a container read the source tree from the host.

The shared anchor for the services is a yml anchor named olympia that merges the environment block, sets the image to ${DOCKER_TAG:-mozilla/addons-server}, and sets pull_policy to never. The comment explains why: the image is sometimes built locally and sometimes pulled from a registry, and compose should always assume the image is already available. The entrypoint is /data/olympia/docker/entrypoint.sh, and the service runs as root at the image level so the entrypoint can fix ownership of files generated during the build, dropping down to a different user afterwards.

Configuration is environment variables, and two of them are mandatory

The environment block is long, and most of it is developer convenience rather than required configuration.

The values that matter for an application are the service endpoints already mentioned, plus a handful of feature switches. SWAGGER_UI_ENABLED is set to true, which turns on the API documentation UI. SKIP_DATA_SEED appears on its own, which is a signal that there is a data seeding step in the startup path and that this environment skips it. The static and media URL prefixes are split, with STATIC_URL_PREFIX pointing at /static-server/ and MEDIA_URL_PREFIX at /user-media/, which separates the bundled front end assets from user uploaded content.

Two entries stand out because they are credentials rather than settings. FXA_CLIENT_ID and FXA_CLIENT_SECRET have no default value in the compose file, which means a local instance cannot start without them being supplied through the .env file that the env_file directive points at. FXA is Firefox Accounts, Mozilla's single sign-on system, so these are the OAuth client credentials the application uses to talk to the account service.

The rest is developer ergonomics. PYTHONDONTWRITEBYTECODE and PYTHONUNBUFFERED are set so that Python does not write .pyc files and streams output unbuffered, which matters when you are reading logs from a container. PYTHONBREAKPOINT is set to ipdb.set_trace, so a breakpoint drops into the ipdb debugger rather than the standard one. TERM is set to xterm-256color, and there is a block of HISTFILE, HISTSIZE, HISTIGNORE and HISTCONTROL settings that give the container shell a persistent, deduplicated history of up to 50000 entries. ENV is set to local, which is the marker the application presumably uses to distinguish a local run from staging and production.

The SITE_URL value of http://olympia.test is the local hostname for the site, and it is a .test domain, which is the reserved TLD for local development, so it will never resolve on the public internet.

The container image builds a non-root user with a fixed uid

The Dockerfile is a multi-stage build that starts from a pinned Python image, and the pinning is worth noticing because it is a digest rather than a tag.

The base is python:3.13-slim-bookworm with a sha256 digest appended, so the exact image content is fixed even if the tag moves. The build stage is named olympia, and it sets a build info environment variable, an ENV of build, and a bash shell with logging and error behaviour enabled through the SHELL instruction using the -xue flags.

The user setup is the part that tells you how the project thinks about deployment. A group and a user called olympia are created with a fixed uid and gid of 9500, and the user is given /sbin/nologin as its shell, so the account can never log in interactively. Its home directory is set to /data/olympia rather than the default, which lets the application own paths under a mounted volume. Environment variables point the dependency directories at that home, with DEPS_DIR at ${HOME}/deps and NPM_DEPS_DIR at ${HOME}/node_modules, and a separate variable names the Vite manifest file, which is how the front end build output is located at runtime.

A directory creation step then makes the deps, node_modules and storage directories and chowns them to the olympia user, so the runtime user owns the paths it needs to write to. The WORKDIR is set to that same home directory.

There is a second stage named info, which takes the build arguments for the commit, the Docker version, the build, and the target, and writes them into a build-info.json file. The comment above it explains that these are passed via the bake.hcl file and should not be overridden in the container environment, and the generated file embeds the source repository URL. The repository listing confirms the bake file exists as docker-bake.hcl, along with a separate Makefile-docker and a Makefile-os alongside the ordinary Makefile, which is how the project distinguishes container builds from operating system package builds.

The front end is a Vite rewrite of a jQuery era codebase

The package.json dependency list tells a story about a long transition.

The runtime dependencies are dominated by jQuery and its satellites: jquery at 4.0.0, jquery-ui, jquery-pjax, jquery.browser, jquery.cookie, and a minicolors plugin. Alongside them sit timeago.js, jszip, less at 4.9.1, netmask, and source-map. addons-linter at 10.14.0 is the one dependency with a clear product purpose, since it is Mozilla's own linter for add-on packages, which is what a developer submits to the site.

So the served front end is a jQuery and Less application that is being modernised in place, with Vite and Vitest as the new build and test tooling and a set of JavaScript architecture files alongside it: a babel config, an eslint flat config, a stylelint config, a knip configuration for unused dependency detection, and separate vite and vitest configs. The babel config, babeljs.cfg and a .babelrc all sit at the root, which tells you the old build pipeline is still present alongside the new one.

The scripts reflect a modernising workflow. The check and fix tasks run every matching task in parallel through npm-run-all, and there are paired check and fix scripts for eslint, stylelint and knip. The test task is vitest run, with a watch variant, and jsdom is in the dev dependencies, so the front end tests run in a simulated DOM rather than a real browser. Prettier and eslint-config-prettier handle formatting, eslint-plugin-simple-import-sort enforces import order, and stylelint has a separate configuration for Less files, which is what the less dependency implies.

The practical note for anyone joining the project is that both eras of tooling are live in the same repository. A contribution touching front end code may need to satisfy the legacy build and the new one at the same time.

Security reports go through Bugzilla, not GitHub issues

The README carries an explicit security process, and it is not the one a GitHub user would expect.

The code and its associated production web page are included in Mozilla's web and services bug bounty program. If someone finds a security vulnerability, the instruction is to submit it through the process outlined in the program and FAQ pages, and the README points to the Bug Bounty Onramp page on Mozilla's wiki for further technical details about the application.

The rule that catches people out is the last one. All security related bugs must be submitted through Bugzilla using the web security bug form, and never through a GitHub issue or by email. The repository even contains a marker comment for a security bug inclusion marker that must not be removed, which is the standard way to make the point of the process explicit in the source of a public repository.

That decision is a direct consequence of the fact that this is the code behind a live extension store. A public issue describing a vulnerability in a system that hosts and serves browser extensions would be a disclosure, and the reviewer would be reading it in the open. The repository also carries a SECURITY.md file and a CODEOWNERS file, which is the standard way to route security issues to the right people, and there is a .semgrepignore file at the root alongside a zizmor.yml configuration, the latter being a tool for auditing GitHub Actions workflows.

The bug report location for ordinary, non-security issues is a different repository, github.com/mozilla/addons, which keeps the issue tracker separate from the server code.

Running locally is a documented path, not a one command path

The README does not contain the setup instructions, and it says so. It directs developers and anyone who wants to run the application locally to the setup and configuration documentation, hosted at mozilla.github.io/addons-server under the topics on development and setup and configuration.

The repository structure shows how much there is to that. Beyond the code, the listing holds a settings.py and a settings_test.py at the root, a manage.py, a conftest.py for pytest, a pyproject.toml, a requirements directory, a scripts directory, a private directory, a docker directory, a docs directory, and a tests directory. There are several compose files: docker-compose.yml as the base, docker-compose.override.yml, docker-compose.private.yml, docker-compose.tools.yml and docker-compose.ci.yml, which together describe the local, private, tooling and continuous integration variants of the stack. There is a Dockerfile and a docker-bake.hcl for multi-image builds.

The Python side of the tooling is configured in pyproject.toml, with ruff handling linting and formatting. The configuration is specific: line length 88, target version py313, and an exclude list covering dependencies, node_modules, docs, static, git and the migrations directory. The lint rules are extended with bugbear, pycodestyle errors, pyflakes, isort and flake8-quotes, and the ignore list is annotated with reasons, including that DTZ is skipped because the code runs in UTC, and that blind-except is allowed because the majority of matches are intentional in health checks and best-effort tasks. The remaining ignored rules are marked as currently failing and roughly ordered by how often they fire.

The documentation has a page on building and running services, referenced from the Dockerfile header, which is the right place to look for how the container pieces fit together. The Docker Compose path is the one most likely to get a newcomer to a working system, since it brings up the database, broker, cache and search services together, and the environment file that the compose file expects is a .env in the repository root.

Editorial conclusion

addons-server fits a team that wants to study or fork a working extension marketplace, and an organisation that already runs Django and can absorb a service stack of MySQL, RabbitMQ, Redis, Memcached and Elasticsearch. It is the wrong starting point for a small team that needs only an add-on listing API, and it is the wrong starting point for anyone who cannot run a multi-service stack locally, since the compose file expects a database, a message broker and two cache and search backends before the application starts. Before attempting a local run, read the setup and configuration documentation linked from the repository, confirm the FXA_CLIENT_ID and FXA_CLIENT_SECRET values your instance needs, and decide deliberately whether you want the Docker path or the local Makefile path, because the Makefile targets are written around a full local service set.

Frequently asked questions

What is addons-server and what is it for?

It is the Django application and API that serves addons.mozilla.org, Mozilla's extension marketplace, and the repository is the code for that live service rather than a reusable library. Bug reports for it go to a separate repository at github.com/mozilla/addons.

What services does addons-server need to run?

The Docker Compose configuration shows MySQL for the database, RabbitMQ as the Celery broker, Redis as the Celery result backend, Memcached for caching and Elasticsearch for search, with a Vite front end server published on port 5173. The Python image is built on a pinned python:3.13-slim-bookworm digest.

How do I report a security issue in addons-server?

Through Bugzilla using the web security bug form, and never through a GitHub issue or by email. The code and its production web page are in Mozilla's web and services bug bounty program, and the README points to the Bug Bounty Onramp page for technical detail.

What front end tooling does addons-server use?

Vite for the dev and build scripts and Vitest for the tests running in jsdom, with eslint, stylelint, knip and prettier for checks. The served front end still depends on jQuery 4, jquery-ui, Less and a jQuery-era utility library, alongside addons-linter for validating submitted add-on packages.

What licence is addons-server released under?

The repository licence field reads BSD-3-Clause and a LICENSE file sits at the root, while the packaging metadata in pyproject.toml classifies the olympia distribution under the Mozilla Public License. Both are permissive, but a compliance check should confirm which terms apply to the files you are actually using.

Official sources

  1. License: BSD-3-Clause
  2. mozilla/addons-server on GitHub
  3. Project website
  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/mozilla-addons-server.svg)](https://hysenlabs.com/projects/mozilla-addons-server)

Was this useful?