Mod Storage

New in v1.0.0

Persist settings and data across game sessions (Electron only)

<Callout type="info"> Storage is only available in the desktop (Electron) version. In browser, storage operations are no-ops that return safely without error. </Callout>

The Storage API lets your mod save settings and data that persist across game sessions. Data is stored per-mod in the user's app data directory.

<Callout type="warning"> Common gotcha: `storage.get()` returns a Promise, not the value directly. If you forget await, you'll silently get [object Promise] instead of your data.

javascript
// Wrong β€” val is a Promise object, not your data
const val = api.storage.get('key');

// Correct
const val = await api.storage.get('key');

</Callout>

Save and Load Settings#

javascript
// Save a setting
await window.SubwayBuilderAPI.storage.set('myModEnabled', true);
await window.SubwayBuilderAPI.storage.set('favoriteColor', '#ff0000');
await window.SubwayBuilderAPI.storage.set('userPrefs', {
    volume: 0.8,
    notifications: true
});

// Load a setting (with optional default value)
const enabled = await window.SubwayBuilderAPI.storage.get('myModEnabled', false);
const color = await window.SubwayBuilderAPI.storage.get('favoriteColor', '#000000');
const prefs = await window.SubwayBuilderAPI.storage.get('userPrefs', {});

console.log('Mod enabled:', enabled);

Delete and List Keys#

javascript
// Delete a stored value
await window.SubwayBuilderAPI.storage.delete('myModEnabled');

// Get all stored keys for this mod
const keys = await window.SubwayBuilderAPI.storage.keys();
console.log('Stored keys:', keys); // ['favoriteColor', 'userPrefs']

API Reference#

storage.get(key, defaultValue?)#

Retrieves a stored value.

ParameterTypeDescription
keystringThe key to retrieve
defaultValueanyValue to return if key doesn't exist

Returns: Promise<any> - The stored value or default

storage.set(key, value)#

Stores a value.

ParameterTypeDescription
keystringThe key to store under
valueanyThe value to store (must be JSON-serializable)

Returns: Promise<void>

storage.delete(key)#

Deletes a stored value.

ParameterTypeDescription
keystringThe key to delete

Returns: Promise<void>

storage.keys()#

Lists all stored keys for this mod.

Returns: Promise<string[]> - Array of key names

Data Types#

Storage supports any JSON-serializable data:

javascript
// Primitives
await storage.set('count', 42);
await storage.set('name', 'My Mod');
await storage.set('enabled', true);

// Objects
await storage.set('config', {
    theme: 'dark',
    notifications: true,
    favorites: ['NYC', 'CHI', 'LA']
});

// Arrays
await storage.set('history', [
    { date: '2024-01-01', action: 'installed' },
    { date: '2024-01-02', action: 'configured' }
]);

<Callout type="warning">Functions, DOM elements, and circular references cannot be stored.</Callout>

Mod Isolation#

Each mod's storage is isolated based on the mod ID from your manifest.json:

json
{
    "id": "my-awesome-mod",
    "name": "My Awesome Mod"
}

Keys are automatically namespaced, so storage.set('config', ...) in your mod won't conflict with another mod using the same key name.

Complete Example#

javascript
const api = window.SubwayBuilderAPI;

// Mod settings panel with persistent preferences
const DEFAULT_SETTINGS = {
    showNotifications: true,
    autoSave: true,
    theme: 'auto'
};

// Load saved settings on init
api.hooks.onGameInit(async () => {
    const settings = await api.storage.get('settings', DEFAULT_SETTINGS);
    applySettings(settings);
});

// Settings UI
api.ui.registerComponent('settings-menu', {
    id: 'my-mod-settings',
    component: api.utils.components.createElement(
        'div',
        { className: 'space-y-4' },
        api.utils.components.createElement(api.utils.components.Switch, {
            id: 'notifications',
            defaultChecked: true,
            onCheckedChange: async (checked) => {
                const settings = await api.storage.get('settings', DEFAULT_SETTINGS);
                settings.showNotifications = checked;
                await api.storage.set('settings', settings);
            }
        }),
        api.utils.components.createElement(
            api.utils.components.Label,
            { htmlFor: 'notifications' },
            'Show Notifications'
        )
    )
});

function applySettings(settings) {
    // Apply your mod's settings
    console.log('Applied settings:', settings);
}

Browser Compatibility#

When running in the browser (not Electron), storage operations are safe no-ops:

javascript
// In browser, these work but don't persist:
await api.storage.set('key', 'value'); // Does nothing
await api.storage.get('key', 'default'); // Returns 'default'
await api.storage.keys(); // Returns []

This lets you write code that works in both environments without conditionals.