3DSync

Homebrew for the Nintendo 3DS/2DS family that synchronises saves and files with cloud storage.
Supports Dropbox and Google Drive (bidirectional sync).

settingsOpen Configurator Source Code

Quick Start

  1. Open the configurator and follow the three steps.
  2. Place the downloaded 3DSync.ini on the SD card at /3ds/3DSync/3DSync.ini.
  3. Install output/3ds-arm/3DSync.cia or run 3DSync.3dsx from the Homebrew Launcher.
  4. Launch 3DSync. It will sync all configured paths — press START to exit.

Configuration

The INI file lives at /3ds/3DSync/3DSync.ini.

Dropbox
[Dropbox]
Token=<access token from configurator>
add_to_driveGoogle Drive
[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.


Sync Paths

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 Sync Logic

Bidirectional paths ([Paths] / [ShallowPaths]) compare each file against the local mtime, the Drive MD5 checksum, and the manifest 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 — press A to keep 3DS version (upload) or B to keep 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.

Manifest file

/3ds/3DSync/manifest.json is stored only on the SD card. Delete it to force a full re-upload on the next run.

{
  "/3ds/Checkpoint/saves/TitleA/001.sav": {"mtime": 1716905520, "md5": "abc123", "id": "driveFileId"},
  "/roms/nds/saves/game.sav":             {"mtime": 1716910000, "md5": "def456", "id": "anotherFileId"}
}

add_to_driveGoogle Drive App Setup

  1. Go to Google Cloud Console.
  2. Create a project and enable the Google Drive API.
  3. Create an OAuth 2.0 Web application credential (Client ID + Client Secret).
  4. Add the redirect URI: https://vllni.github.io/3DSync/configurator.html
  5. 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.

Building

Requires devkitPro with 3DS support.

make

Output: output/3ds-arm/3DSync.cia and output/3ds-arm/3ds/3DSync/3DSync.3dsx.

Full credit to Kyraminol for the original project. Extended by michvllni with Google Drive support, refresh-token auth, and full bidirectional sync.