# RetroAssembly, a browser cabinet that keeps your ROMs and saves in sync

> RetroAssembly is a TypeScript and React Router application that runs RetroArch compiled to WebAssembly in the browser, presents your own ROM files as a cabinet of box art, and stores save states in the cloud or in a self-hosted instance. It can run as the hosted service at retroassembly.com or as your own Docker container on port 8000.

**arianrhodsandlot/retroassembly** — The personal retro game collection cabinet in your browser. Join us on Discord https://discord.gg/gwaKRAYG6t

- Repository: https://github.com/arianrhodsandlot/retroassembly
- Website: https://retroassembly.com
- Stars: 1,152 · Forks: 58
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/arianrhodsandlot-retroassembly

## Your own ROM files, not a catalogue of somebody else's

RetroAssembly is described as the personal retro game collection cabinet in your browser, and that phrase is the design brief. The idea is a piece of furniture, a cabinet you open and browse, rather than a list of files in a folder or a grid of links. The README lists supported platforms including NES, SNES, Genesis, GameBoy and arcade machines, and the project topics add the Atari 2600, Game Boy Advance, Game Boy Color, Mega Drive, Virtual Boy and more to that list.

The content is yours. Getting started says to log in and create a personal game library by uploading your own ROM files, then select any game from that library to launch it directly in the browser. The first run does not require an account on the hosted version beyond a login, and the README points new users at a set of demo games to try the interface before uploading anything.

The cabinet metaphor shows up in the details. Box art and covers are auto-detected rather than uploaded, so a ROM dropped in with the right metadata produces a recognisable cartridge cover. The navigation is spatial, and the README makes a point of that: you can move through the library with a keyboard or a gamepad, using the same kind of directional control you would use on a console. That is the difference between a file browser with a preview pane and something that feels like a shelf you walk along.

## RetroArch in WebAssembly is the engine under the cabinet

The emulation layer is RetroArch compiled to WebAssembly, and the project topics list retroarch, retroarch-wasm and retroarch-web alongside webassembly. That single architectural choice explains most of the behaviour you get, including the parts that are pleasant and the parts that are a constraint.

The pleasant part is the feature set that comes with RetroArch itself. Save states are the obvious one, and the README describes saving and synchronizing at any point and resuming later, with the in-game menu used to save progress so it is synchronized for you. Rewind is another, listed with the wry note that some emulators allow you to rewind gameplay, which is a genuinely rare console feature to have on a phone. Retro-style shaders are there as well, listed as visual effects that enhance the experience, and the separate screenshots in the README show a library view, a games view, a platform view, a ROM view and a menu view, with desktop and mobile variants of each.

The constraint is the one implied by WebAssembly. The README lists an on-screen virtual controller so you can play on the go even without a physical gamepad, and that is the direct answer to the fact that a browser cannot read a console's inputs the way native software can. Performance is bounded by what a browser tab will do, and the project targets many platforms at once, which is a different engineering problem from targeting a desktop OS.

## The hosted version and the self-hosted container

There are two ways in, and the README presents them as a choice of setup rather than a preference. Option 1 is the official hosted version, described as recommended for most users and suitable if you want to start quickly without any setup. The steps are short: visit retroassembly.com, optionally explore the library and try the demo games, log in, upload your ROM files, then launch any game from your library. Once you are playing, the in-game menu is what saves your progress, and that save is synchronized for you.

Option 2 is self-hosting with Docker, described as the route for advanced users who want full control, prefer to host their own instance, have privacy concerns, or want to customize the deployment. The README points to the quick start on the project's Docker Hub page rather than reproducing it, so the actual run command lives there. What the repository does give you is the Dockerfile, and it tells you the two things that matter for a deployment: the port and the volume.

```dockerfile
FROM ${PROD_IMAGE} AS production
WORKDIR /app
VOLUME ["/app/data"]
EXPOSE 8000
CMD ["node", "--run=start"]
```

So an instance listens on port 8000 and keeps its state in a directory mounted at /app/data. Anything you put in that path has to survive container restarts, and the base images are node 26.5.0 on slim for the build and node 26.5.0 on alpine for the runtime, with pnpm 12.11.2 installed globally for the workspace.

The project is MIT licensed, with the licence file at the repository root under the name license.

## One codebase, three runtimes: Node, workerd and the browser

The package.json is where the ambition of the deployment story becomes visible. This is a pnpm workspace, built with React Router, and the scripts are arranged in triplets. There is a plain build, a build:node and a build:workerd, with build:node and build:workerd both defined as node --run=build. The same pattern repeats for dev and for serve: a base dev script, a dev:node and a dev:workerd, and a base serve script, a serve:node and a serve:workerd.

The serve:workerd variant is the interesting one, because it points at wrangler dev --port=8000, which means the same application can be run against a Cloudflare worker runtime locally, while serve:node runs node dist/server/serve.js for a conventional Node server. The wrangler.template.json file at the repository root and the @cloudflare/vite-plugin dependency support that path.

The server side is small and deliberate. The runtime dependencies are better-sqlite3, hono and openid-client, so the HTTP layer is Hono, the storage is SQLite through better-sqlite3, and there is drizzle.config.ts at the root for the schema layer, with a src/databases directory copied into the runtime image. There is a setup script, a tag script and a check-lockfile script, and the end-to-end tests run under Playwright while unit tests use the Node test runner:

```json
"test": "playwright test -c tests/e2e --tsconfig=tests/e2e/tsconfig.playwright.json",
"test:unit": "node --test tests/unit/*.test.ts"
```

There is also a workers adapter package, @hono/cloudflare-workers, and a Node adapter, @hono/node-server, which is how one Hono application serves both runtimes.

## A login system that is only half described

The README contains a section on authentication that is commented out in the source, and it is the more revealing part of the documentation. It describes replacing password login with a single OpenID Connect provider for Node.js and Docker deployments, and it lists the environment variables needed to turn it on:

```bash
RETROASSEMBLY_RUN_TIME_OIDC_ISSUER=https://id.example.com
RETROASSEMBLY_RUN_TIME_OIDC_CLIENT_ID=retroassembly
RETROASSEMBLY_RUN_TIME_OIDC_CLIENT_SECRET=replace-with-client-secret
```

The callback URL to register with the provider is given in the same place, along with the scopes requested by default and the requirement that the provider return the user's username in preferred_username. The openid-client dependency in package.json matches the feature.

Two things follow. The first is that a self-hosted instance is expected to sit behind a real identity provider rather than a shared account system, which is the sensible shape for something that stores personal game data. The second is that the section is inactive in the README as published, so treat the exact variable names as the documented intention rather than a guarantee, and verify them against the current code before you wire an identity provider into a deployment.

The rest of the documentation is thinner still. There is a docs/ directory in the repository, and the hosted version links to a /demo page, a /login page and a demo game library, but the README does not walk through the upload formats, the cover art matching rules, the supported platform list beyond the names, or how a save state is scoped to a user. Those are the details you would want before committing to it.

## What it is not, and when to pick something else

The boundary is legal and practical, and both matter. RetroAssembly does not ship games. You upload the ROM files you own, and the project is a cabinet and a runner for them. That is a different product from the hosted game catalogues that stream licensed titles, and it means the value here is the interface, the emulator integration and the save synchronisation rather than a library of titles.

The comparison to make is with running RetroArch itself in a browser. That route gives you the same emulation core and none of the cabinet, the box art, the spatial navigation or the synchronized saves, and it makes you manage the storage and the interface yourself. RetroAssembly's approach is the opposite: it takes the emulator as a dependency and spends its effort on the collection experience around it. If your interest is in tweaking emulator settings, shader parameters or core overrides, a desktop RetroArch install does that job with more control; if your interest is in playing your own collection on a phone, this is the faster path.

The other practical limit is that emulating older consoles in a browser is not free, and the project covers a wide platform range at once, so per platform performance will differ. A device that struggles with one console may still be fine with another, and the on-screen controller exists for exactly that situation. There is no server-side rendering of games here; the emulator runs on the client, and the server's job is storage, accounts and sync.

## Conclusion

RetroAssembly suits people who own a shelf of legal ROM dumps and want them on any device, including a phone, with a cabinet-style interface instead of a file list, and it suits anyone who wants to self-host rather than hand a third party their ROM collection. It is the wrong tool if you want a storefront of games you do not own, since the whole model is that you upload your own files, and it is the wrong tool for a machine where WebAssembly emulation will not run smoothly, because the emulator itself is a port of RetroArch rather than a native build. Before deploying your own instance, verify that the container image can be pulled from Docker Hub, confirm the data volume at /app/data is persistent, and check the release tag, since the newest one is v7.260719.1051 from 2026-07-19 against a last push on 2026-10-16.

## FAQ

### How do I start using RetroAssembly?

The README offers two setups. The hosted route is to visit retroassembly.com, log in and upload your own ROM files, then launch a game from your library. The self-hosted route uses Docker, with the quick start documented on the project's Docker Hub page.

### How do I self-host RetroAssembly and what port does it use?

The Dockerfile in the repository exposes port 8000 and declares a volume at /app/data, with the container command set to node --run=start. The runtime image is node 26.5.0-alpine and the build uses pnpm 12.11.2.

### Which consoles does RetroAssembly support?

The README names NES, SNES, Genesis, GameBoy and arcade among the supported platforms, and the project topics list the Atari 2600, Game Boy Advance, Game Boy Color, Mega Drive and Virtual Boy as well. The README links to a fuller supported platforms section.

### Does RetroAssembly let me save my progress?

Yes. The README says you can save and synchronize at any point and resume later, using the in-game menu to save so it is synchronized for you. Some emulators also allow rewinding gameplay.

### Can I play RetroAssembly without a gamepad?

Yes. The README lists an on-screen virtual controller for playing on the go even without a physical gamepad. Navigation through the library also works with a keyboard, since the interface is built around spatial navigation.

## Sources

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

---

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