37 3.06 User Data
github-actions[bot] edited this page 2026-11-13 10:06:18 +00:00

User Data

The User Data concept applies only to the desktop (Electron) application. The web app stores data in browser storage (IndexedDB and localStorage) instead. See 3.05-Web-App-vs-Desktop for web vs desktop differences. For an overview of how import, export, backups, and sync work from a user perspective, see 4.23-Managing-Your-Data.

What Data Is Included

A full backup or export is a restorable snapshot of the application model: tasks (active and archived), projects, tags, time-tracking state, global configuration, notes, reminders, metrics, simple counters, planner and board state, task repeat configurations, issue-provider settings, plugin user data, and both archive tiers (recent and old). It is not a byte-for-byte copy of every local database.

Device-local support data is deliberately outside that snapshot. Examples include device-local crash-safe editor drafts (localStorage SUP_LOCAL_DRAFT_*), operation-log transport metadata, the internal import-recovery slot, the Local REST API access token (local-rest-api-token), and sync-provider private configuration stored in the separate sup-sync credential database (credentials and encryption key material). Conversely, issue-provider settings inside the application model can contain API credentials or tokens.

Normal backup and export files are plaintext JSON, even when sync encryption is enabled. Treat them as sensitive: protect them like the work data and credentials they may contain. The anonymized/privacy export masks known field names, but it is not a credential-safety boundary: inspect it before sharing and remove any remaining provider or plugin credentials, tokens, and private content.

Project duplication

Duplicate in a project's menu copies its tasks, subtasks, notes, sections and recurring task configurations into a new project. Each copied recurrence is independent of the original, and copied task instances use the new configuration. Editing or deleting the original recurrence does not affect the copy.

Copied recurrences retain their schedule, pause state and scheduling progress. Paused recurrences and those with no current task instance are copied too.

Purpose of the User Data Folder

The User Data Folder is the application data directory where the desktop app stores:

  • All user data, settings, and configurations
  • Automatic backups
  • Custom theme file (styles.css)
  • The Local REST API access token (local-rest-api-token)
  • IndexedDB and localStorage data (managed by Electron)

Default Location by Platform

Platform Location
macOS ~/Library/Application Support/superProductivity/
Windows C:\Users\<YOUR_USER_NAME>\AppData\Roaming\superProductivity/ or %APPDATA%\superProductivity
Linux ~/.config/superProductivity/

The backup path is shown in the UI under Settings → Automatic Backups (including the backups/ subfolder) and is printed when the app is started from the command line.

Custom Folder Location

You can specify a custom user data directory using the --user-data-dir command-line parameter:

superproductivity --user-data-dir=/path/to/my/data

Trailing slashes are stripped. The custom path is used instead of the default for the session.

Snap Packages (Linux)

For Snap packages on Linux, the app uses the SNAP_USER_COMMON directory so that data is not accessed by the Snap update process. The effective path is $SNAP_USER_COMMON/.config/superProductivity (or the app name equivalent).

Flatpak Packages (Linux)

Flatpak keeps data inside the package sandbox. The app sets no custom path here; Flatpak redirects XDG_CONFIG_HOME into the sandbox, so the effective path is ~/.var/app/com.super_productivity.SuperProductivity/config/superProductivity/. The exact location is shown in Settings → Automatic Backups.

Two consequences follow from the sandbox:

  • A second, non-Flatpak install (AppImage, .deb, Snap) reads a different directory and will not see this data. Move between packaging formats via export/import, not by installing alongside.
  • Sync or backup targets outside the sandbox need an explicit filesystem permission, granted with Flatseal or flatpak override. Without it the app reports a permission error; paths inside ~/.var/app/ always work.

Windows Store

The Windows Store build may use a different path that includes the Windows Store package identifier (under Local\Packages\...\LocalCache\Roaming instead of Roaming). This depends on whether Windows virtualizes the package: virtualized packages have their AppData writes redirected into LocalCache, while full-trust ones write to the plain Roaming path. Settings shows whichever location actually exists on your machine, so check there rather than assuming either one.

Directory Structure

backups/ Subdirectory

  • Stores automatic backup files (JSON).
  • Location: {userData}/backups/.
  • On desktop, automatic backup files use the filename format YYYY-MM-DD_HHmmss.json.

styles.css (optional)

  • Custom theme file for desktop styling.
  • Must be created manually by the user and placed directly in the User Data Folder (not in a subfolder).
  • Loaded by the main process and injected into the renderer; invalid CSS may fail to load and is logged.
  • Watched while the app runs: creating, editing, or replacing the file re-applies it to the open window without a restart. Emptying or deleting the file removes the styles from the open window right away.

local-rest-api-token (optional)

  • Created the first time the Local REST API (see 3.01-API) is enabled, directly in the User Data Folder. Written with mode 0600 (owner read/write only) on macOS and Linux; on Windows it inherits the folder's ACL.
  • Contains the API access token in plain text — a credential, not settings. It is per device: it is not part of the application state, so it is never synced, and a device restored from a backup or an import keeps (or generates) its own token.
  • Not included in automatic backups, manual backups, "Export data", or import — those carry application state only. A device that imports another device's data still uses its own token, and existing scripts keep working with the token shown in Settings → Misc → Access Token.
  • Is included in a cold copy of the whole User Data Folder (file-level profile backup, disk image, folder sync). Such a copy therefore contains a live API credential: keep it as private as the profile itself, or regenerate the token afterwards from Settings → Misc.
  • Deleting the file is safe: the next time the API is enabled — or the token is read in settings — a new one is generated. Scripts holding the old token then receive 401.

IndexedDB and localStorage (Electron-managed)

  • IndexedDB databases and localStorage entries live in platform-specific locations under the userData path.
  • Managed by Electron; do not move or edit these files manually.

File Types and Formats

JSON Backup Files

  • Format: YYYY-MM-DD_HHmmss.json for desktop automatic backups.
  • Content: A restorable application-model snapshot serialized as plaintext JSON.
  • Naming: Timestamped by local date and time (e.g. 2025-01-15_143022.json).

CSS Theme File

  • File: styles.css (exact name required).
  • Purpose: Custom CSS for theming; user-created and optional.

IndexedDB Databases

  • SUP_OPS: Operation-log persistence for the runtime snapshot, retained operations, causal metadata, archives, and internal recovery state. The executable schema and upgrade owners are src/app/op-log/persistence/op-log-db-schema.ts and src/app/op-log/persistence/db-upgrade.ts; access is owned by OperationLogStoreService and its persistence adapters.
  • pf: Legacy database used for migration and recovery.
  • SUP: Database of version 12 and older. If the app starts with no data and finds data here that was never migrated, it offers to download a copy and import it. The app never writes to it.
  • sup-sync: Device-local sync-provider credentials, private configuration, and encryption key material, owned by src/app/op-log/sync-providers/credential-store.service.ts. This database is not part of application-model backups or exports.
  • SUPPluginCache: Plugin cache.
  • SUP_RECENTLY_DELETED: Device-local "Recently deleted" trash (searchable from Search, and listed at the bottom of History). It holds a copy of each task deleted in the last 30 days, with its subtasks, whether it was deleted on this device or arrived as a delete from sync. Plainspace tasks, blank tasks and tasks deleted together with their project are not kept. Entries expire after 30 days or when emptied. Emptying applies only to the device you empty it on, and deletes made before it are not added again, even by a later full re-sync. The database is never synced and is not part of backups or exports, so a new device only lists the deletes it later receives through sync. Owned by src/app/features/tasks/recently-deleted/recently-deleted-store.service.ts.

The retired conflict journal database (SUP_CONFLICT_JOURNAL) and its local clear marker are deleted on startup without export. This removes only old review entries; tasks, pending operations and backups are retained. If an older tab holds the database open, cleanup completes after that connection closes.

localStorage Keys

UI and app state stored with keys such as:

  • SUP_UI_HELPER, SUP_ACTION_LOG, SUP_LAST_ERROR_ACTION_LOG
  • SUP_IS_PROJECT_LIST_EXPANDED, SUP_IS_TAG_LIST_EXPANDED
  • DARK_MODE, SUP_NAV_SIDEBAR_EXPANDED, SUP_NAV_SIDEBAR_WIDTH, SUP_RIGHT_PANEL_WIDTH
  • SUP_BOTTOM_NAV_SLOT: the phone bottom navigation's second destination. Device-local, never synced.
  • SUP_IS_ADD_TO_BOTTOM, and others (see storage-keys.const.ts for the full set).
  • SUP_LOCAL_DRAFT_*: Device-local crash-safe editor drafts, one entry per in-progress edit, keyed by SUP_LOCAL_DRAFT_${entityType}:${entityId}. They back the fullscreen note editor so unsaved edits survive a crash or force-close, and are never synced or uploaded and excluded from backups and exports — a draft is transient device state, not application data. A draft is removed as soon as it is redundant: when the edit is saved or discarded, when the note is deleted on this device, and when the dataset is replaced wholesale (JSON import, SuperSync restore). Crash leftovers whose note is never reopened are pruned on app start once older than 14 days.

Backup Behavior

Automatic backups: When enabled in settings, the app creates a backup on a schedule (default: every 5 minutes). The interval and backup subdirectory are not configurable in the UI. Storage location depends on platform:

Platform Where automatic backups are stored
Electron (desktop) {userData}/backups/ as timestamped JSON files (YYYY-MM-DD_HHmmss.json)
Android A native app-private SQLite store (SupKeyValStore, keys backup / backup_prev for the latest and previous slots), separate from the WebView IndexedDB so it survives IndexedDB eviction
iOS Capacitor Filesystem API: latest and previous JSON files in Directory.Data
Web No automatic file backups; use "Export data" to download a file manually

On desktop, the Maximum backup files setting caps the number of timestamped automatic backup files kept in the backups/ folder. Older files are deleted when the cap is exceeded. At the default cap, cleanup keeps the 30 most recent backup files plus up to one newest backup per day for the current day and previous 20 days, when files for those days exist. The exact file count can be lower because the daily backups often overlap with the 30 most recent files.

On mobile (Android/iOS), each automatic backup moves the latest backup into the previous slot, unless the latest holds fewer than half as many tasks (archived included) as the previous one: then the previous backup is kept until your data grows back, so a near-empty restart cannot push out both full backups; the one kept holds at least half as many tasks as the larger one. After a deliberate large delete, the previous slot therefore keeps the older, larger backup for a while; if the app restarts near-empty in that time, that older backup is the one kept, not the smaller one made after the delete.

On mobile (Android/iOS), if the app launches with no local data but a usable on-device backup exists — the typical "blank app after the system evicted WebView storage" case — the latest backup is restored automatically on startup, without a prompt (if only the previous backup is usable, the app asks first, naming its task and project counts), with a snackbar reporting how many tasks and projects were restored. This only happens when the live store is genuinely empty; a deliberate in-app "delete all data" leaves a valid (empty) state and is not auto-restored. Restore latest automatic backup also remains available manually in Settings -> Sync & Backup -> Automatic Backups, which shows a Last backup timestamp so you can confirm you are protected; the manual restore replaces the current local data after confirmation. On desktop, there is no automatic restore: if the app starts with no data at all and backups exist, it asks whether to restore the newest one, naming the folder, its timestamp, and how many tasks and projects it holds so you can judge it before accepting. If sync is configured, restored data (auto or manual) is treated as a backup import: on the next sync it propagates to and overwrites your other synced devices, so use it as a recovery action rather than a routine one.

Manual backups: (1) Create manual backup in Settings → Sync & Export creates a backup using the same mechanism as automatic backups (platform-dependent location). (2) Safety backups are created automatically before certain sync operations; the app keeps a limited number of slots (e.g. two most recent, one first from today, one first from day before). (3) Export data downloads a full application-model snapshot as JSON to a path you choose (or the browser download folder on web).

What is included: Backups and exports contain the restorable application model described above, including both archive tiers when archives are requested. They do not copy the retained operation log, causal/transport metadata, device-local crash-safe editor drafts (localStorage SUP_LOCAL_DRAFT_*), internal import-recovery slot, separately stored sync-provider credentials and encryption key material, or the Local REST API access token (local-rest-api-token) — see above. A separate import backup (the newest of up to three recovery points) is stored locally in IndexedDB (import_backup). The app captures it before replacing local state through a file import or the sync conflict action Use Server Data (on a device's first SuperSync sync: Use my account's tasks). A successful Use Server Data replacement shows a persistent Undo action that restores this backup; interrupted replacements offer the same recovery action when sync resumes. The Undo remains available after an app reload while that same backup is still present. It is not included in exports; Browse backups lists it with the other recovery points (see 2.02-Restore-Data-From-Backup).

The application-model snapshot can still contain private work content and issue-provider API credentials or tokens. Its JSON serialization is not encrypted by sync encryption; protect normal backup/export files. The anonymized/privacy export is best-effort, so inspect it and remove any remaining credentials, tokens, or private content before sharing it for diagnostics. With AI assistant capture switched on (see 3.01-API#agent-task-capture-mcp), backups and exports also contain the capture private key (sync.captureKey), which opens the captures waiting on the SuperSync server; the anonymized export masks it.

Import and Export

Export: Export produces a snapshot of the current state at the time of export. The file is plaintext JSON containing (or wrapping) the restorable application-model state. Relationships are preserved by ID references (e.g. tasks reference projectId and tagIds; subtasks reference parentId). Export is available via Settings → Sync & Export → Import/Export (e.g. "Export data" / download backup).

Import: The app accepts a full backup in the same format (complete application-model state, optionally wrapped with timestamp and version). Supported structures: (1) the raw complete state object, or (2) a wrapper object with data, timestamp, and crossModelVersion where data is the complete state. Legacy V1 format (e.g. config + tasks array) is detected but no longer supported; the user is shown an alert that migration is not supported. Before applying import, the app validates the data (structure and cross-entity relationships). If validation fails, automatic repair may run when possible (e.g. fixing orphaned tasks, invalid project/tag references, missing archive structures). If the snapshot records a different sync-encryption state from the current app, the app may show a confirmation dialog before importing. That warning is about how the imported state would configure subsequent sync; it does not mean the backup file itself is encrypted. After import, current state is replaced; archive data is written to IndexedDB. See 2.02-Restore-Data-From-Backup for how to perform a restore.

Legacy Local Data Migration Retirement

Automatic in-place migration of local data from Super Productivity v16 or older (the legacy pf database) to the operation-log store still works today. It will retire in the first release after January 23, 2027.

After retirement, if your local data has not yet been migrated, first run the last release that supports this migration, let it finish, and then upgrade to the latest release. That bridge release's version and download instructions will be added when it is known. Data already migrated to the operation-log store needs no bridge step.

This retirement applies to local data on a device, including browser storage. Supported older JSON backup imports remain supported through Import from file; the existing unsupported V1 format exception above still applies. Remote sync formats are separate and are not retired by this notice. See 2.02-Restore-Data-From-Backup for JSON restore instructions.

Sync

Strategy: The app is local-first and records changes as operations, then adapts that log to different transports. SuperSync sends operations through an ordered server API. File providers use the default v2 monolithic format, which rebuilds and uploads the current snapshot, both archive tiers, and retained operations on an operation-bearing upload. The opt-in v3 split format stores those parts separately, so ordinary operation uploads do not rewrite snapshots between compactions. See the maintainer field guide's transport comparison.

Conflict resolution: Conflicts are detected using vector clocks (same entity changed concurrently in two places). Resolution first applies explicit archive/delete precedence and safe disjoint-field merging. Remaining overlaps use last-write-wins (LWW): the newer operation timestamp wins; an exact tie uses stable client-ID ordering. When the local or merged result must dominate both histories, the app emits the appropriate update, archive-win, or delete-win operation for the next upload. Identical conflicts are auto-resolved without user action. The app may show a dialog to choose Keep local or Keep remote in two situations: first-sync, where both local and remote already have data, and when automatic resolution stops on changes it cannot merge safely (SYNC_MULTI_ENTITY_UNSUPPORTED) — see 3.08-Sync-Integration-Comparison. Either choice replaces the entire losing dataset, not just the conflicting entities. After resolution, state is validated and repaired as needed.

User-Editable Vs System-Managed

User-editable:

  • styles.css — Create and edit for custom themes.
  • Backup files — Can be restored via Settings → Sync & Export → Import/Export → Import from file (see 2.02-Restore-Data-From-Backup).

System-managed (do not edit manually):

  • IndexedDB databases.
  • localStorage entries.
  • Active backup files (readable as JSON but manual editing is not recommended).

Size Limits and Quota

Client-side IndexedDB

  • When QuotaExceededError occurs, the app triggers emergency compaction (24-hour retention instead of 7 days) and uses a circuit breaker to avoid infinite retries.
  • Browser/OS quota and available disk space apply.

SuperSync Server (if Used; beta)

  • Default quota: 100 MB per user.
  • Automatic cleanup when quota is exceeded.

Permissions

  • The app needs normal read/write access to the User Data Folder. Default locations are under the user's home or app data directory; no administrator/root rights are required.
  • Plugins that need native file-system or process access require the nodeExecution permission and explicit consent in the Electron desktop app. Built-in and uploaded/community plugins may request it. Uploaded plugins are identified as unverified third-party code in the native prompt; granting access lets that plugin run code with the same machine access as your user account. See 2.21-Manage-Plugins.

Recovery and Repair

Automatic Data Repair

  • Validation runs at several points in the operation lifecycle.
  • Repairs issues such as orphaned tasks, invalid references, and inconsistent relationships; creates REPAIR operations for the log.
  • If a task exists both as a live task and in the archive, repair keeps the live task and drops the archived copy.

Disaster Recovery

  • If the main database (SUP_OPS) is missing or corrupted, the app attempts to load from the legacy pf database and run genesis migration.
  • If recovery fails, a full re-sync (or restore from backup) is required.
  • If migrating the legacy pf database fails, the migration dialog reports the error and waits. It also offers Continue without old data, which starts the app with an empty store instead of dead-ending on the error at every restart. Nothing is deleted: the pf database stays on disk and only gets a _migration_skipped marker, so migration and recovery stop picking it up. The automatic pre-migration backup can then be imported normally, and the untouched pf database remains a second copy for manual recovery.

Backup Restoration

  • Restore from a backup file in backups/ via Settings → Sync & Export → Import/Export → Import from file. See 2.02-Restore-Data-From-Backup.

Sync State Corrupted

  • When a synced operation cannot be applied cleanly, the app flags the sync state and re-validates; a full re-sync restores consistent state.

Configuration and Versioning

  • Public application configuration is part of the model snapshot in SUP_OPS; local UI settings also use localStorage (SUP_* and related keys). Sync-provider private configuration and key material live separately in the sup-sync credential database.
  • Database schema: Treat src/app/op-log/persistence/op-log-db-schema.ts and src/app/op-log/persistence/db-upgrade.ts as the executable source of truth; do not rely on a copied version number or store inventory in documentation.
  • Application version: Defined in the build (e.g. src/environments/versions.ts), not stored in the User Data Folder.
  • Backup files: Each JSON file carries a restorable application-model snapshot; desktop automatic backup naming includes date and time.

Application Access (Desktop)

  • Main process: Path obtained via Electron app.getPath('userData'); custom path set with app.setPath('userData', path) when --user-data-dir or Snap logic is used.
  • Renderer: Path is exposed via IPC (e.g. getUserDataPath()).
  • Backups and file sync: Node.js fs APIs (e.g. readFileSync, writeFileSync, readdirSync, statSync, unlinkSync) are used for backup and local file sync.

Notes

  • Web app: Data lives in browser storage only; there is no User Data Folder. See 3.05-Web-App-vs-Desktop.
  • Do not live-sync this folder: Generic WebDAV or cloud-folder tools can copy Electron's IndexedDB/LevelDB files and lock files while they are changing, which risks a corrupt or unusable profile and also uploads plaintext backups plus device-local credentials. Use Super Productivity's built-in sync for multiple devices. For a cold profile backup, fully close the app first, copy the folder as one sensitive backup, and restore it only while the app is closed.
  • Themes: Example themes and theme-creation guidance: super-productivity-themes.

Task Priority Compatibility

Task backups may contain numeric priorities (1, 2, 3) or the equivalent legacy strings (low, medium, high). Both are preserved when imported, synced, duplicated, or restored from the archive. Display, sorting and filtering use their meaning; selecting a different priority writes a number. Clearing a priority writes null.

Saved priority filters on the same device retain their selected level after reload, including filters saved by builds that used the legacy strings.

Older priority-aware builds accepted only one encoding. Every participating device needs the compatibility repair; updating one device cannot repair the reader installed on another. The affected master builds all reported 19.1.0, so that version alone does not identify a compatible client. The normal release process must publish the repair under a distinct future version. SuperSync does not currently enforce a minimum app version.