# raindropio/app: one JavaScript codebase for the Raindrop.io web app, browser extensions and desktop app

> The Raindrop.io repository is a monorepo whose single source tree is built into a web application, an Electron desktop app and extensions for six browser targets, with webpack configuration per target and separate vendor flags. The README is short, but the build matrix it documents explains most of the repository's structure, including the Safari path that needs an Xcode project and a version script.

**raindropio/app** — Source code of web app and browser extensions

- Repository: https://github.com/raindropio/app
- Website: https://app.raindrop.io
- Stars: 1,614 · Forks: 176
- Language: JavaScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/raindropio-app

## One source tree, four kinds of artefact

The repository is a monorepo for the Raindrop.io web app, the browser extension and the desktop app, and the package description calls the product an all-in-one bookmark manager.

The structure that follows from that is in the tree. There is `src/` for the shared source, `build/` for the webpack configuration with one file per target, `functions/` for serverless functions, and `vercel.json` at the root, which is the deployment configuration for a serverless platform. The rest is conventional: a `.babelrc`, an `.eslintrc`, a `jsconfig.json`, a `.node-version` pinning the Node version, a `package-lock.json` and a `TODO.md`.

The interesting engineering decision is that the build is parameterised by vendor rather than forked. There is one extension configuration, `build/extension.js`, and the target is selected with an environment flag, `--env vendor=chrome` and so on, with separate configurations for the web app, `build/web.js`, and the Electron app, `build/electron.js`.

So the browser extensions are one codebase with a vendor switch rather than six copies, and the web and desktop apps are separate webpack entry points over the same source. The package manifest marks the project with `"sideEffects": false`, which tells the bundler that the modules can be treated as side effect free for tree shaking, a meaningful statement for an extension that has to stay small.

## The build matrix, target by target

The README's build table is the most useful document in the repository, and it is short enough to reproduce.

The first instruction is that you must run `npm i` before calling any of the commands, and then the table maps a target to a command and a note:

| target | command | notes |
|----------|---------|-------|
| web | `npm run build` | |
| electron | `npm run build:electron` | |
| chrome | `npm run build:extension:chrome` | |
| edge | `npm run build:extension:edge` | |
| firefox | `npm run build:extension:firefox` | Saved to `dist/firefox/prod` |
| opera | `npm run build:extension:opera` | |
| safari | `npm run build:extension:safari` | Then open the build/xcode project |

The note column is where the platform specific knowledge lives. Firefox output lands in a different directory, `dist/firefox/prod`, because the Firefox add-on format wants a different package layout. Safari is the odd one out, because the script does more than compile JavaScript.

There is also an aggregate target, `build:extension`, which chains the Chrome, Edge, Firefox, Opera, Safari and Safari iOS builds in sequence, which is what a release build would run. The Safari iOS variant exists as its own target, `build:extension:safari-ios`, so the iOS Safari extension is a separate artefact rather than a flavour of the desktop one.

## Safari leaves the JavaScript behind

The Safari target is the most interesting entry in the matrix, and the difference is visible in the package manifest. The Safari build is not a single webpack invocation, it is a webpack invocation followed by a step inside the Xcode project directory:

```json
"build:extension:safari": "webpack --config build/extension.js --env production --env vendor=safari && cd 'build/xcode/Save to Raindrop.io' && ./version.sh"
```

So the JavaScript is compiled as usual, and then a version script runs inside the Xcode project, and the README instructs you to open the `build/xcode` project afterwards. The Safari extension is delivered as a native Xcode project that embeds the compiled bundle, which is why the build stops at a project rather than a distributable archive.

That is not a preference, it is how Safari extensions are packaged. The same reason explains the development reset script the README provides, with the warning that it removes all Safari settings:

```sh
rm -rf ~/Library/Containers/com.apple.Safari/Data/Library/Safari/*
rm -rf ~/Library/Containers/com.apple.Safari/Data/Library/WebKit/*
rm -rf ~/Library/Developer/Xcode/DerivedData/Save_to_Raindrop.io-*(N)
defaults delete com.apple.Safari 2>/dev/null
```

The first two lines clear the Safari container's saved state and the WebKit cache, the third clears the derived data for the extension, and the last removes the Safari preferences domain. That is the price of developing a Safari extension, and the warning is placed above the commands rather than below them, which is the right place for it.

## Size is a checked budget, not a hope

Browser extensions have a size limit and a review process that punishes bloat, and the package manifest treats bundle size as something you measure.

The `size` script builds the web bundle with the webpack profiler writing JSON statistics to `dist/web-stats.json`, then runs the bundle analyser over that file. There is a matching `size:extension:chrome` script for the extension bundle, so the same measurement exists for both targets.

That is a small but meaningful piece of engineering. A bundle that quietly grows by a megabyte every quarter is the standard failure mode of a shared web and extension codebase, and having the measurement wired into the manifest as a first class command is how you catch it while the change that caused it is still in review.

The development scripts follow the same pattern of one config per target. `npm run local` serves the web app through the webpack dev server with the web configuration, `npm run local:extension:chrome` and `npm run local:extension:opera` serve the extension with the vendor flag, and `npm run local:electron` serves the desktop app. There is also `local:prod`, which builds the production bundle and serves `dist/web/prod` on port 80, which is the closest thing to a production smoke test that does not involve deploying.

## Browser floors, and the development wrinkle they cause

The README lists the supported browsers with the reason for each floor, and those reasons are the interesting part.

Chrome 67 and later, because older versions do not support SameSite cookies. Safari 11 on OS X 10.11 and later, because older versions do not support rest properties in objects. Firefox 55 and later, for the same rest properties reason. Edge 80 and later, because earlier versions were not the Chromium based Edge.

So the floors are the point at which a language feature or a cookie behaviour the application depends on became available, not an arbitrary support policy.

That SameSite dependency has a practical consequence in development, and the README names it. For the Chrome extension development flow you are told to turn off the `same-site-by-default-cookies` flag in Chrome's browser flags. The extension and the web app are served from different origins during development, and the cookie rules that make the product work in production get in the way locally.

It is a small reminder that a bookmark manager is a web application with a login, and the cross origin cookie rules are part of its architecture rather than a detail of the build.

## What this repository is and is not

The first thing to say is that there is nothing here to install as a dependency. The package is named `app`, its `main` is `index.js`, and it exists to be built into Raindrop.io, so it is an application repository rather than a library, and the practical way to use it is to run it, not to import it.

The second is that the server side is small and separate. The `functions/` directory with a `vercel.json` indicates a serverless deployment, which fits a bookmark service, where the storage is in the user's own cloud accounts and the server is mostly an index and an API. The `src/` tree is what the browser and the extensions run, and the desktop app is the same source in an Electron shell.

The third is that this is a single product's monorepo, so its structure is a good model to copy and a poor library to depend on. The vendor parameterised build, the per target size measurement and the platform notes are the transferable parts.

On the state of the project, the version in the manifest is 5.8.3, the release list shows a single `latest` tag pointing at 5.8.3 on 2026-10-13, and the last push to the repository was on 2026-10-13 with the repository not archived. The licence is MIT, with a `LICENSE.md` file at the root, and the author of the package is Rustem Mussabekov. A monthly release cadence for a bookmark manager that ships six browser extensions and a desktop app is brisk, and it is the reason the build matrix is documented as carefully as it is.

## Conclusion

Adopt this repository if you want to understand or contribute to Raindrop.io, since it is the whole product source and the build matrix tells you exactly which artefacts exist. Do not adopt it as a component for your own product, since there is no published package, the code is an application rather than a library, and the build targets are hard coded to six browser vendors and an Electron shell. Verify first that the browser version you run is above the stated floors, Chrome 67, Safari 11, Firefox 55 and Edge 80, and that your development environment can produce the platform you need, because the Safari build leaves the JavaScript behind and hands you an Xcode project to open.

## FAQ

### What is in the raindropio/app repository?

It is a monorepo holding the Raindrop.io web app, the browser extension and the desktop app, with the shared source in `src/`, per target webpack configuration in `build/`, serverless functions in `functions/` and a `vercel.json` deployment configuration. The package is MIT licensed and describes the product as an all-in-one bookmark manager.

### How do I build the Raindrop.io extensions?

Run `npm i` first, then use `npm run build:extension:chrome`, `:edge`, `:firefox`, `:opera` or `:safari`. The Firefox output is saved to `dist/firefox/prod`, the Safari build also runs a version script inside the Xcode project in `build/xcode` and then you open that project, and `npm run build:extension` chains all of the vendors including a Safari iOS build.

### How do I run the Raindrop.io app locally?

With `npm run local` for the web app through the webpack dev server, `npm run local:extension:chrome` for the extension, and `npm run local:electron` for the desktop app. The Chrome extension flow additionally asks you to turn off the `same-site-by-default-cookies` flag in Chrome's browser flags.

### What are the minimum supported browsers for Raindrop.io?

Chrome 67 and later, because older versions do not support SameSite cookies, Safari 11 on OS X 10.11 and later, because older versions do not support rest properties in objects, Firefox 55 and later for the same reason, and Edge 80 and later because earlier versions were not the Chromium based Edge.

### How does the Raindrop.io project check bundle size?

The package manifest defines a `size` script that builds the web bundle with the webpack profiler writing JSON statistics to `dist/web-stats.json` and then runs the bundle analyser over it, with a matching `size:extension:chrome` script for the extension build.

## Sources

- [License: MIT](https://github.com/raindropio/app/blob/master/LICENSE)
- [Project website](https://app.raindrop.io)
- [raindropio/app on GitHub](https://github.com/raindropio/app)
- [README](https://github.com/raindropio/app/blob/master/README.md)
- [Releases](https://github.com/raindropio/app/releases)

---

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