Homebrew for the Nintendo 3DS/2DS family that synchronises saves and files with cloud storage.
Supports Dropbox and Google Drive (bidirectional sync).
Full credit to Kyraminol for the original project. Extended by michvllni with Google Drive support, refresh-token auth, and full bidirectional sync.
- Open the configurator and follow the three steps.
- Place the downloaded
3DSync.inion the SD card at/3ds/3DSync/3DSync.ini. - Install
output/3ds-arm/3DSync.ciaor run3DSync.3dsxfrom the Homebrew Launcher. - Launch 3DSync. It will sync all configured paths and press START to exit.
The INI file lives at /3ds/3DSync/3DSync.ini.
[Dropbox]
Token=<access token from configurator>[GoogleDrive]
ClientId=<OAuth client ID>
ClientSecret=<OAuth client secret>
RefreshToken=<refresh token from configurator>
FolderId=<optional root folder ID>FolderId restricts all Drive operations to one folder. Leave it out to use Drive root.
Four INI sections control which local paths to sync and how:
| Section | Direction | Subdirs |
|---|---|---|
[Paths] |
Bidirectional | Yes |
[ShallowPaths] |
Bidirectional | No |
[UploadPaths] |
Upload only | Yes |
[UploadShallowPaths] |
Upload only | No |
Each entry has the form RemoteName=LocalPath:
[Paths]
Checkpoint=/3ds/Checkpoint/saves
roms/nds/saves=/roms/nds/saves
[UploadPaths]
Backup=/3ds/MyGame- RemoteName is the Drive folder path (use
/for nesting, e.g.roms/nds). - LocalPath is the absolute path on the SD card.
- Bidirectional entries use a manifest (
/3ds/3DSync/manifest.json) to detect which side changed. - Upload-only entries always push the local file to Drive and never download.
Bidirectional paths ([Paths] / [ShallowPaths]) compare each file against:
- The local file modification time (
st_mtime). - The Drive file MD5 checksum from the Drive API.
- The manifest — a local JSON file that records the mtime and MD5 from the last successful sync.
| Local changed? | Drive changed? | Action |
|---|---|---|
| No | No | Skip (up to date) |
| Yes | No | Upload local → Drive, update manifest |
| No | Yes | Download from Drive → local, update manifest |
| Yes | Yes | Conflict — 3DS shows a prompt: press A to keep the 3DS version (upload) or B to keep the Drive version (download) |
| Local missing | Drive exists | Download from Drive |
| Local exists | Drive missing | Upload to Drive |
| Both missing | — | Remove stale manifest entry |
"Changed" means the mtime (local) or MD5 (Drive) differs from the last manifest entry.
On first run (no manifest entry yet), the local file is uploaded and the manifest is initialised.
Bidirectional paths preserve the relative directory structure on Drive.
Example: local file /3ds/Checkpoint/saves/TitleA/001.sav synced with remote name Checkpoint appears on Drive at Checkpoint/saves/TitleA/001.sav.
Upload-only paths still use flat filenames (saves_TitleA_001.sav) for backwards compatibility.
/3ds/3DSync/manifest.json is a plain JSON file stored only on the SD card:
{
"/3ds/Checkpoint/saves/TitleA/001.sav": {"mtime": 1716905520, "md5": "abc123", "id": "driveFileId"},
"/roms/nds/saves/game.sav": {"mtime": 1716910000, "md5": "def456", "id": "anotherFileId"}
}Delete this file to force a full re-upload on the next run.
If the 3DS system clock differs from the Drive server time by more than 60 seconds, 3DSync will print a warning. Inaccurate timestamps may cause unnecessary uploads or missed downloads — keep the 3DS clock synchronised.
- Go to Google Cloud Console.
- Create a project, enable the Google Drive API.
- Create an OAuth 2.0 Web application client (Client ID + Client Secret).
- Add the redirect URI:
https://vllni.github.io/3DSync/configurator.html. - Use the configurator to authenticate; it performs PKCE and stores the refresh token.
Note: Apps in Testing mode issue refresh tokens that expire after 7 days. Publish the app or add your Google account as a test user to avoid frequent re-authentication.
Requires devkitPro with 3DS support.
makeOutput: output/3ds-arm/3DSync.cia and output/3ds-arm/3ds/3DSync/3DSync.3dsx.