# opencollective-frontend: the React and Next.js app behind Open Collective

> opencollective-frontend is the Next.js and React application that serves opencollective.com, talking to the Open Collective API over GraphQL with Apollo. It suits contributors who want to work on a real payments-adjacent product, and anyone who wants to see a large GraphQL client application in the open.

**opencollective/opencollective-frontend** — Open Collective's Frontend. A React app powered by Next.js.

- Repository: https://github.com/opencollective/opencollective-frontend
- Website: https://opencollective.com
- Stars: 896 · Forks: 456
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/opencollective-opencollective-frontend

## The app you are looking at when you visit opencollective.com

The scope is a single production web application rather than a library. The project is described as Open Collective's Frontend, a React app powered by Next.js, and it is the code behind the site at opencollective.com, with the homepage given as opencollective.com. It is a private npm package, so it is not on the registry as a consumable dependency, and the version field in the package metadata reads 2.2.0, which matches the most recent GitHub release from 2018-05-17. That gap between the release tag and the actual state of the code is the first thing worth internalising about this repository. The tagged releases stop in 2018, with v2.1.1 and v2.1.0 in the same week, and the last push was on 2026-10-19, so the project is very much alive and simply does not tag releases. Anyone pinning to v2.2.0 would be installing code from eight years ago, and the sensible reading is that the main branch is the only meaningful reference point.

## GraphQL over Apollo, with the schema as a lint input

The data layer is GraphQL with Apollo Client, and the repository topics name graphql as well as react, nextjs and webpack. The dependency list pins @apollo/client at 3.14.1 and @graphql-typed-document-node/core at 3.2.0, and the latter is the piece that gives you typed documents, which means a GraphQL operation in the code is checked against the schema at compile time rather than at run time. The schema also reaches the linter. The instructions for keeping things in sync include a step to update the GraphQL schema for ESLint by running a dedicated script, and the repository has a graphql.config.js at the root, which is the file that tells the tooling where the schema lives and how to resolve it. That combination, a typed document node plus an ESLint rule set driven by the schema, is the pattern a large GraphQL client application tends to converge on, because the alternative is discovering that a field was renamed from a runtime error in production. The API is a separate service, and the frontend requires access to it, which is the first thing to sort out before anything else works.

## A component library built on Radix and published separately

There is a components directory at the root and a published package that goes with it. The components are built on the Radix UI primitives, and the dependency list is a long run of Radix packages at specific versions: accordion, alert-dialog, checkbox, collapsible, dialog, dropdown-menu, hover-card, label, popover, radio-group, select, separator, slot, switch, tabs, toast and tooltip. Below that sit the styling and interaction libraries, with @emotion/is-prop-valid, @popperjs/core for positioning, @dnd-kit/core, sortable and utilities for drag and drop, and a set of icon packages including styled-icons in boxicons, fa-brands and fa-solid variants plus react-simple-icons. The components are published to npm separately as @opencollective/frontend-components, and the publishing procedure is documented in the readme with three steps: check the currently published version, trigger the publishing script with the new version number following semver, and review the changes before confirming. The configuration for what gets included in that package lives in a file under the publish-components script directory. Publishing is restricted to core team members, which is a deliberate way of keeping a shared component library from diverging across the app.

## Local development means pointing at staging, or at your own API

The setup is short and has one important quirk. The prerequisite is Node.js version 20.x and npm 9.0.0 or newer, with nvm recommended and the install step being a clone into a folder dedicated to opencollective projects, followed by npm install:

```bash
git clone git@github.com:opencollective/opencollective-frontend.git opencollective/frontend
cd opencollective/frontend
npm install
```

Once the dependencies are in place the dev server is started with npm run dev. The environment variable file has two options. By default the app connects to the Open Collective staging API and you do not have to change anything, and the readme explains that because captcha is not configured by default in local development, you need to create an account on the staging site first and can then log in on your local frontend. The alternative is to clone, install and start the separate opencollective-api repository and point the frontend at it with an API_URL and an API_KEY in a .env file. The dev server is then started with npm run dev. Note the version mismatch between the readme, which says Node 20.x and npm 9, and the package metadata, which declares engines of node 24.x and npm 11.x, and the Dockerfile, which is built from node 24.21. The metadata is the newer of the three, and the readme instruction about updating it when it is outdated is the reason the readme says what it says about fresh pairs of eyes.

## Tests split between Jest and Cypress, plus Playwright

The test story has three parts, and the split is the interesting detail. For pages and components the instruction is npm test, and the package metadata shows jest.config.js at the root. End-to-end tests use Cypress and have a dedicated guide in the docs directory, with cypress.config.js at the root. There is also a playwright.config.ts in the repository, so a second end-to-end runner is present alongside Cypress, which suggests a migration or a parallel setup rather than a single tool. The update commands are the part to remember, because a failing snapshot in a large app is usually a stale snapshot rather than a regression. To update Jest snapshots you run the test:update script, translation files are refreshed with the langs:update script, and the GraphQL schema used by ESLint is refreshed with the graphql:update script. Each of those three regenerates a derived artefact that is checked into the repository, and each is a source of merge conflicts if one contributor forgets to run it. Coverage is configured through a codecov.yml at the root, and the repository carries a sentry setup with a set of configuration files, an error filter file and constants, which tells you the production app is instrumented.

## The Dockerfile shows the app talks to five services

The container definition is the clearest inventory of what the frontend depends on. The image is built from node:24.21 with the working directory set to the frontend source, and the Cypress binary install is skipped with an environment variable set to 0 so the image does not carry a browser download it will not use. Dependencies are installed before the source is copied, which keeps the layer cache useful. Then the build arguments appear, and each one is a separate service endpoint. There is an API_URL pointing at the staging API, an INTERNAL_API_URL pointing at a separate direct staging API host, an IMAGES_URL for the images service, a PDF_SERVICE_URL for the PDF service and an ML_SERVICE_URL for the machine learning service, alongside an API_KEY. The production mode is set through the node environment build argument, and the image runs npm run build, then prunes the dev dependencies, exposes the port and starts the app. For a project of this size that is a satisfyingly small number of dependencies for a frontend, and the split between the public API and the internal direct API is the kind of detail that only matters to someone who has to configure a deployment.

## Contributing comes with a bounty programme and a core team gate

The contribution path is unusual enough to be worth describing, because it changes who the project works for. This repository is part of the Open Collective bounty program, described as an opportunity to get paid to contribute to open source, with the reason given plainly: the engineering team is small and they are always looking for new contributors, and the program exists to solve issues that could otherwise be neglected. The code style rules are short. Prettier and ESLint are used, and the project says it likes great commit messages and clean git history, with the detail in CONTRIBUTING.md. The readme also opens with a request to improve the instructions themselves, saying that if you see a step that could be improved or is outdated, please update it, because the team rarely goes through that process itself and a recent experience makes you the best candidate to improve the steps for other users. Deployment and publishing are both gated to core team members, since the project is deployed to staging and production with Heroku and the component publishing script needs core team access. The repository also holds an AGENTS.md, a .claude directory, a .agents directory, a devcontainer setup, a Dockerfile and a renovate.json.

## Conclusion

opencollective-frontend is a good fit for a contributor who wants to work on a real production application with a GraphQL API, a component library published to npm, and a bounty programme that pays for the issues nobody has time for. It is the wrong project for a team that wants a template to copy, since it is bound to a specific API, a specific set of endpoints and a specific design system, and it is the wrong project for anyone who cannot run the API locally. Before contributing, get the API running alongside it rather than relying on the shared staging instance, because the staging API is shared and its captcha is not configured locally, and read the environment variable list, since the Dockerfile shows that the app talks to at least five separate services. The licence is MIT, the last push was on 2026-10-19, and the package version has sat at 2.2.0 since 2018.

## FAQ

### How do I set up the opencollective-frontend locally?

You need Node.js 20.x and npm 9.0.0 or newer according to the readme, though the package metadata declares node 24.x and npm 11.x. Clone the repository into a folder dedicated to opencollective projects, run npm install, and then start the dev server with npm run dev. By default the app talks to the Open Collective staging API and no environment change is needed.

### Can I log in to the local frontend?

Yes, but you need an account first. Because captcha is not configured by default in local development, the readme tells you to create an account on the staging site first and then use that account to log in on your local frontend. Alternatively you can clone, install and start the separate opencollective-api repository and point the frontend at it with API_URL and API_KEY in a .env file.

### How are tests run and kept in sync?

Page and component tests run with npm test using Jest, and end-to-end tests use Cypress with a dedicated guide in the docs directory, with a Playwright config also present at the root. Three generated artefacts have their own update commands: test:update for Jest snapshots, langs:update for translation files and graphql:update for the GraphQL schema used by ESLint.

### How are the frontend components published?

The components are published to npm as @opencollective/frontend-components, and publishing requires core team membership. The steps are to check the currently published version, run the publish-components script with the new version number following semver, and then review the changes. What gets included in the package is configured in the publish-components config file under the scripts directory.

### What services does the opencollective-frontend depend on?

The Dockerfile lists build arguments for an API URL pointing at the staging API, a separate internal API URL, an images service URL, a PDF service URL and an ML service URL, along with an API key. The image is built from node:24.21, skips the Cypress binary install, runs the build, prunes the dev dependencies and starts the app.

## Sources

- [License: MIT](https://github.com/opencollective/opencollective-frontend/blob/main/LICENSE)
- [opencollective/opencollective-frontend on GitHub](https://github.com/opencollective/opencollective-frontend)
- [Project website](https://opencollective.com)
- [README](https://github.com/opencollective/opencollective-frontend/blob/main/README.md)
- [Releases](https://github.com/opencollective/opencollective-frontend/releases)

---

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