Migrate Local Data to Remote Server
Learn how to migrate your data from a local UnderControl desktop instance (Personal tier with SQLite) to a remote server, enabling cross-device access and sync.
Prerequisites
- UnderControl desktop app with local data you want to migrate
- A remote UnderControl server deployed and accessible (see Docker Compose deployment)
- The
udCLI installed on your machine (CLI documentation) - Accounts on both the local and remote servers
Overview
When using UnderControl desktop with the Personal tier, your data is stored in a local SQLite database. If you want to access your data from multiple devices (e.g., laptop and phone), you need to migrate your data to a remote server.
The ud migrate command fetches data from one server (source) and creates it in another (target), automatically handling ID remapping for cross-references like expense-to-budget links.
Steps
Step 1: Install the CLI
Check if the ud CLI is already installed:
ud --version
If not installed, you can install it via any of these methods:
- Desktop app: Open the Settings page and click the Install button in the CLI configuration section
- Other install methods: See the CLI download page
For full CLI documentation, see the CLI Tool page.
Step 2: Set Up Contexts
The CLI uses "contexts" to manage connections to different servers. You need to set up two contexts: one for your local instance and one for the remote server.
Log in to your local instance:
ud login --name local --api-url http://localhost:4000
Log in to your remote server:
ud login --name remote --api-url https://your-server.example.com
Verify both contexts are configured:
ud config get-contexts
You should see both local and remote listed.
Step 3: Run a Dry Run
Before migrating, run a dry run to see what will be migrated without making any changes:
ud migrate --from local --to remote --dry-run
This shows the count of entities that would be migrated:
Migration dry run (no data will be written)
accounts fetched=3 created=3
budgets fetched=5 created=5
expenses fetched=120 created=120
incomes fetched=45 created=45
tasks fetched=200 created=200
boards fetched=2 created=2
saved-queries fetched=5 created=5
task-views fetched=3 created=3
Step 4: Run the Migration
Once you're satisfied with the dry run, execute the actual migration:
ud migrate --from local --to remote
The command migrates entities in dependency order:
- Accounts and Budgets (no dependencies)
- Expenses and Incomes (reference accounts/budgets)
- Tasks with notes and links
- Boards, Saved queries, and Task views
Cross-references (e.g., an expense linked to a budget) are automatically remapped using the new IDs from the target server.
Step 5: Verify the Migration
Log in to your remote server through the web browser and verify your data is present. Check a few tasks, expenses, and budgets to make sure everything looks correct.
Advanced: User Mapping
If your local and remote accounts have different user IDs (for example, if you registered with different emails), you can provide a user mapping file:
Create a user-map.yaml file:
users:
"local-user-uuid-here": "remote-user-uuid-here"
Run the migration with the user map:
ud migrate --from local --to remote --user-map user-map.yaml
To find your user IDs, check the profile/settings page on each instance.
Advanced: Selective Migration
You can migrate specific entity types only:
# Migrate only tasks and expenses
ud migrate --from local --to remote --entities tasks,expenses
# Migrate only financial data
ud migrate --from local --to remote --entities accounts,budgets,expenses,incomes
Available entity types: accounts, budgets, expenses, incomes, tasks, boards, saved-queries, task-views
Tips
- Always run
--dry-runfirst to preview what will be migrated - The migration creates new data on the target server — it does not delete anything from the source
- If migration is interrupted, you can safely re-run it (duplicate detection may vary by entity type)
- After migration, you can switch your desktop app to point to the remote server for ongoing use