Saves & States
Two different things, often confused:
- Save files: the in-game save (
.srm,.sav,.save, etc.). What the game writes when you use the in-game save feature. Works across emulator cores that share the format. - Save states: a full memory snapshot of the emulator at a moment in time. Emulator-specific. A SNES9x state won't load in bsnes.
Both are per-user per-ROM and stored under /romm/assets/<user>/<rom>/. They follow you across browsers and devices.
Uploading
You can upload save files for your own games (handy for importing from real hardware via Retrode/GB Operator or from another emulator). Same flow for states, with an optional screenshot attachment that's autogenerated when the state is created from in-browser play.
Selecting on launch
If a ROM has multiple saves or states, RomM presents a picker before the emulator loads.
In-emulator behaviour
Saves and states you create in the emulator are written straight back to the server, so there's no "forgot to upload" step. The player also asks you to confirm before navigating away from a running game, so you don't lose unsaved progress.
In-game, the Export and Import save buttons are replaced by a single Load save or state picker, which opens with the same Saves and States tabs as the launch screen. A state applies on the fly; picking a save restarts the game from that save. Either one replaces what's running, so you're asked to confirm first.
A Sync save button appears alongside it when automatic save sync is off, to upload the current save on demand.
Automatic save sync
A save syncs automatically with the server seconds after it's stored in the browser. The player watches the emulator's SRAM while you play and uploads a new version as soon as one appears, so your progress is saved even if the tab is closed or the browser crashes. Leaving the player uploads anything the server doesn't have yet.
This is on by default. Set emulatorjs.auto_save_sync to false to go back to uploading only on save and quit:
Each upload is the entire save file, and some games save constantly. On a small instance you won't notice, but you might with a lot of users and large saves. This is instance-wide, set by the server owner, and only affects in-browser play. Save states already upload as you create them and aren't affected either way.
An upload the server doesn't take (it's down, the connection dropped) is held in your browser with the screenshot taken when the game wrote it, and retried later. The player tells you whether it was kept, so a "kept for later" message means the progress is safe even though the save isn't on the server yet. Held saves belong to the account that made them, so a shared browser won't hand your progress to whoever signs in next.
Save slots
Saves are organized into slots, the same model used by the sync clients, so the same slots show up whether you played in the browser or on a device.
autosaveis where ordinary play goes, and it keeps a capped history, so it prunes itself as you play.- A named slot, created on launch, keeps every version. Use one when you want a checkpoint you can always come back to.
Each slot lists its newest version first, tagged Latest, with older versions folded behind a toggle. A version written in the browser carries a screenshot from the moment it was written, shown as its thumbnail.
The server prunes a slot to MAX_SAVES_PER_SLOT (50 by default, 0 to disable the cap). A client that asks for a tighter limit of its own gets the tighter of the two. Saves uploaded without a slot, such as one you imported by hand, are never pruned.
Device sync
Saves and states can sync to/from registered devices (Grout on muOS, DeckRommSync on a Deck, etc.). Covered in depth in the ecosystem section:
- Device Sync Protocol: wire-level reference
- SSH Sync: server owner config
- Argosy Launcher/Grout: per-app setup
Once a device is paired and sync is running, saves made on the device appear server-side within a couple of sync cycles (default: 15 minutes). Conflicts (same ROM saved on two devices between syncs) surface as two separate save entries, so pick which to keep.
Format/core compatibility
Saves
Save files are usually format-interchangeable across cores for the same platform but not always.
| Platform | Format | Usually-compatible |
|---|---|---|
| NES | .sav |
Yes, across FCEUmm/Nestopia |
| SNES | .srm |
Yes, across SNES9x/bsnes |
| Genesis/Mega Drive | .srm |
Yes |
| Game Boy/GBC/GBA | .sav |
Yes, across Gambatte/mGBA |
| N64 | .srm, .eep, .fla |
Yes but per-type: the right file must be uploaded |
| PSX | .srm (memory card) |
Yes, across Mednafen/PCSX cores |
| Saturn/Dreamcast | Varies | Check core docs |
If you're moving saves between the bundled EmulatorJS and a stand-alone emulator (RetroArch, Dolphin, PPSSPP), it usually works for mainline cores.
States
Save states are always core-specific. A SNES9x state will not load in bsnes. If you switch cores, your states become useless.
Practical advice: stick to one core per platform if you use states heavily, or use save files (which are interchangeable) as your primary persistence.
RetroAchievements and states
If you use RetroAchievements in hardcore mode, loading a save state disables achievement tracking for that session. This isn't enforced locally but the RA server will stop crediting achievements. Use save files (the in-game save) instead of states if you care.
Troubleshooting
- Save uploaded but the game doesn't see it: wrong format for the core. Check the compatibility table above, then re-upload or switch cores.
- State loads a corrupted frame: state was saved by a different build of the core. If the emulator bundle updated, old states may not load cleanly. Re-create or start a fresh save.
- Save disappears after play: the emulator didn't write a save at all. Use the in-game save feature rather than relying on the emulator flushing on its own, and check that automatic save sync is on.
- Can't upload, "file too large": reverse proxy limit. Raise
client_max_body_size/proxy-body-size(see Reverse Proxy).
More in Troubleshooting.