Open-source project
ppy/osu-web avatar
ppy/osu-web

osu!web: the Laravel application behind the osu! website

the browser-facing portion of osu!

1,166 stars439 forksPHPAGPL-3.0

At a glance

What is it?
The browser-facing half of the osu! rhythm game, a long-lived Laravel and TypeScript codebase that serves a game with player accounts, beatmaps, scores and a shop, run on Octane with MySQL, Redis and Elasticsearch. Two policies in the README shape any contribution: the design is already decided, and the project closes contributions that were aided by an AI model.
Who is it for?
osu!web suits a PHP engineer who wants to work on a large, real Laravel application with a public backlog, a live production site and an international contributor base. It does not suit a contributor whose workflow depends on an AI model, because the README states that contributions created by, documented by, or aided by AI or LLM usage will typically be closed and locked, and it does not suit a team that cannot work under AGPL-3.0 with the trademark carve-out.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly PHP, 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

What osu!web is, and the two policies that shape contributions

osu!web is the browser-facing portion of osu!, the website of the osu! rhythm game. It is a PHP project built on Laravel, with a TypeScript and webpack front end, and the site it serves is at osu.ppy.sh.

The README's contributing section is unusually direct, and two paragraphs in it determine whether a contribution is worth writing.

The first is about design. The project welcomes all contributions, but says to keep in mind that the full site is already designed, with mock-ups. If you wish to work on a new section, you should open a ticket and they will give you what you need from a design perspective. And if you want to make changes to the design, the recommendation is to open an issue with your intentions before spending too much time, to ensure no effort is wasted.

The second is about tooling. The team believes in human contributions, and the README says that any contribution, be it an issue report or a pull request, which is created by, documented by, or aided by AI or LLM usage will typically be closed and locked without further discussion.

That is an unusual policy to find in a README, and it applies to all three of creation, documentation and assistance. It is a decision by the maintainers about how they want contributions to arrive, and it is the first thing any prospective contributor to this project needs to know.

The project is licensed under AGPL version 3 or later, and the README adds a note that the licence does not cover the usage of the osu! or ppy branding in any software, resources, advertising or promotion, because that is protected by trademark law.

The stack in the front end, and a Laravel that has absorbed a decade

The `package.json` shows a front end that carries several generations of web development at once, and reading it tells you about the project's history.

The newest layer is React, with `@shopify/hydrogen-react` at a 2024 version and the Shopify storefront API client, and `@hotwired/turbo` for page navigation. The oldest is Bootstrap 3 at 3.3.6, with jQuery and its plugins, jQuery UI, and the blueimp file upload widget. Between them sits d3 at 7, lodash, autosize, clipboard-polyfill, and the Twemoji and Font Awesome icon sets.

Then there is a CoffeeScript loader and coffeescript itself, which is a fossil of an earlier era of this codebase, and the build tooling: webpack with a copy plugin, a CSS minimiser, a fork TypeScript checker, chokidar for watching, and dotenv for environment variables.

So the front end is a Laravel Blade and JavaScript application that has been extended rather than replaced, with React and Hydrogen added for the newest surfaces while Bootstrap 3 and jQuery still serve the older ones. That is the normal shape of a long-lived web application, and it is the single most important thing to understand before contributing to it.

The PHP side shows the same history. There is a `composer.json` and `composer.lock`, a `phpcs.xml` for the code standard, `phpunit.xml` and `phpunit.dusk.xml` for the two test tiers, a `karma.conf.js` for the JavaScript tests, a `webpack.config.js`, and a `tsconfig.json`. The Docker side has a `Dockerfile.development` and a `Dockerfile.deployment`, a `compose.yaml`, a `build.sh` and a `deploy.sh`, and a `DEPLOYMENT.md`.

The repository also pins its toolchain versions with `.node-version` and `.php-version` files, which is what keeps a large contributor base on a consistent build.

The development stack, and what each service is for

The `compose.yaml` file describes the local development environment, and it is a good map of what the application depends on.

The base environment is a set of shared environment variables: the application key, the database connection string pointing at a `db` service with the `osu` database, the Redis host, the Elasticsearch host with a separate one for solo scores, the broadcast driver set to redis, the notification redis host, a GitHub token, a passport public key, and a URL for the beatmap difficulty lookup cache.

Then the services. The `php` service runs Octane in watch mode, and it sets `shm_size: '2gb'` with the comment that it is for chromium. The `php-dusk` service runs the same command with a dusk.local environment and its own Octane state file, which is how the browser tests get a separate application instance. The `assets` service runs the asset build, with the command overridable through an environment variable. The `job` service runs a job worker. The `migrator` service runs migrations and depends on the database being healthy. And there is a `testjs` service that runs the JavaScript tests under a profile, with extra volumes for the test assets and builds.

Two of the services are prebuilt images rather than local code. The `beatmap-difficulty-lookup-cache` is the `pppy/osu-beatmap-difficulty-lookup-cache` image with its port mapped. The `notification-server` is the `pppy/osu-notification-server` image, which depends on both Redis and the database being healthy.

That last one is the interesting piece of architecture. Beatmap difficulty calculation and the notification delivery are separate services with their own images and their own release cadence, and the web application calls them over HTTP. Splitting those out is what keeps a change to difficulty calculation from requiring a deployment of the whole site.

The environment file, and what the application talks to

The `.env.example` is a catalogue of the application's dependencies, and it is worth reading as an architecture document.

The first entries are rate limiting, with a global API throttle of 1200 requests per second and a separate one for score downloads at 10 per second, both with a named bucket. Then the application basics: the URL, the environment, debug flag, key, log level, and optional Sentry configuration.

Clockwork is enabled by default for local development, with a note that it provides local insights at a path and adds a slight performance overhead.

Then the storage tier, in order: the database host and credentials, Redis for sessions, a separate Redis for the cache, and Memcached with a persistent id, a username and a password, which is the persistent cache tier for the things you do not want to recompute. Then the osu! API key, and the broadcast, cache and session drivers, all of which default to redis but are commented out so the local default is the file or database driver.

The mail configuration is the standard Laravel mailer shape, with a log driver as the local default so nothing sends mail by accident.

And then the S3 section, which is the biggest part. There is a central bucket, a replay bucket, an avatar bucket, a preview bucket and a screenshots bucket, each with its own key, secret, region and base URL, plus an endpoint and a path-style option for a local S3-compatible service. The default avatar URL points at a local image, and the screenshot bucket has a shared secret and a legacy id cutoff.

So the storage story is: user uploads and generated assets live in S3 buckets, one per category, with the local development environment pointing at a path-style endpoint. The number of buckets is a reasonable proxy for how many distinct asset classes the game produces.

Localisation, tests and the contribution workflow

The badges in the README header tell you what the project measures itself on. There is a tests workflow, a lint workflow, a Crowdin badge for localisation, and a Discord dev chat badge.

Localisation is handled through Crowdin, and the contributing section sends people there directly, calling it the way to help with localisation efforts. The repository has a `crowdin.yml` at the root and a `resources/` directory for the translated strings. The `lang/` pattern is what you would expect for a Laravel application with translations, and it means a contributor who speaks a language the site is missing can do useful work without touching PHP at all.

The two test tiers are the PHP unit tests under `phpunit.xml` and the Dusk browser tests under `phpunit.dusk.xml`, and the compose file shows them running against a real application instance with a 2GB shared memory allocation for chromium. Dusk is a browser test framework, so those tests drive a real browser against the running site, which is the only way to test the parts of the interface that exist only in a browser.

The JavaScript tests are separate, run under Karma through the `testjs` service, and the `lint` script covers the JavaScript and TypeScript sources under `resources/js` and the Karma tests, with the type check run through the webpack fork checker rather than as a separate script.

For anyone looking for a first contribution, the README points at the list of open issues filtered by the good first issue label, and the process is: search before opening, open a ticket for a new section, open an issue before a design change, and read `CONTRIBUTING.md` for the code standards expected of pull requests.

The README also notes the standards are not set in stone, and invites feedback on the code structure, the libraries used and the contribution process itself.

Where osu!web is the wrong place to work

The first wrong case is a contributor whose workflow depends on an AI model. The README says plainly that any contribution created by, documented by, or aided by AI or LLM usage will typically be closed and locked without further discussion. That covers issue reports, pull requests and documentation alike, so it is not a matter of submitting generated code, it is a matter of the project not wanting that kind of contribution at all.

The second wrong case is a developer who wants to redesign something. The site is already designed with mock-ups, and the README asks you to open an issue with your intentions before spending time, so a design proposal that has not been discussed first is a proposal that will be closed.

The third is a team that wants to deploy osu!web as their own product. The licence is AGPL-3.0-or-later, and the README spells out the consequence, that if you want to use any code, design or artwork from the project you have to attribute it and make your project open source under the same licence. On top of that, the branding carve-out means the osu! and ppy names cannot be used in software, resources, advertising or promotion.

The fourth is a developer looking for a modern stack. A Laravel application with Bootstrap 3, jQuery, CoffeeScript, React, Hydrogen, Octane, MySQL, Redis, Elasticsearch and a set of sibling microservices is a large and particular codebase. The good parts of it are the parts of a real production system, and the cost is the same as any large legacy application.

The fifth is someone expecting a quick contribution to land. The project has a public backlog with good first issues, an international community, and an explicit design process, and a ticket usually means a conversation before it means a pull request.

Editorial conclusion

osu!web suits a PHP engineer who wants to work on a large, real Laravel application with a public backlog, a live production site and an international contributor base. It does not suit a contributor whose workflow depends on an AI model, because the README states that contributions created by, documented by, or aided by AI or LLM usage will typically be closed and locked, and it does not suit a team that cannot work under AGPL-3.0 with the trademark carve-out. Before starting, read `CONTRIBUTING.md` and `SETUP.md`, and if your change touches the design, open an issue with your intentions first, since the project asks you to do that to avoid wasted effort.

Frequently asked questions

What is osu!web and what does it do?

It is the browser-facing portion of osu!, the website of the rhythm game. It is a PHP application built on Laravel with a TypeScript and webpack front end, and it serves the player accounts, beatmaps, scores and site features at osu.ppy.sh.

Can I contribute to osu!web with AI assistance?

The README states that the team believes in human contributions, and that any contribution created by, documented by, or aided by AI or LLM usage will typically be closed and locked without further discussion.

What licence is osu!web released under?

AGPL version 3 or later. The README adds that using any code, design or artwork from the project requires attribution and making your project open source under the same licence, and that the osu! and ppy branding is excluded because it is protected by trademark law.

What services does the osu!web development environment need?

The compose file runs the PHP application under Octane, a Dusk browser test instance, an assets builder, a job worker, a migrator, a JavaScript test runner, a MySQL database, Redis, Elasticsearch, a beatmap difficulty lookup cache and a notification server.

How do I contribute to osu!web?

Read `CONTRIBUTING.md` for the code standards, use the setup guide in `SETUP.md` for the development environment, look for issues labelled good first issue, open a ticket before working on a new section, and open an issue with your intentions before making design changes. Localisation work is done through Crowdin.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. ppy/osu-web on GitHub
  4. Project website
  5. README
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/ppy-osu-web.svg)](https://hysenlabs.com/projects/ppy-osu-web)

Was this useful?