Skip to content

Data Storage

Efficient data storage is essential for mini program performance and user experience. This guide covers local storage, cloud storage, and best practices for data management.

Local Storage

Mini programs provide persistent local storage APIs with a 10MB limit per app.

Basic Storage Operations

javascript
// Store data (async)
wx.setStorage({
  key: 'userInfo',
  data: { name: 'John', theme: 'dark' },
  success: () => console.log('Stored successfully'),
  fail: (err) => console.error('Storage failed:', err)
})

// Retrieve data (async)
wx.getStorage({
  key: 'userInfo',
  success: (res) => {
    this.setData({ userInfo: res.data })
  },
  fail: () => console.log('Key not found')
})

// Synchronous operations (recommended for simple data)
try {
  wx.setStorageSync('settings', { theme: 'dark', lang: 'en' })
  const settings = wx.getStorageSync('settings')
  wx.removeStorageSync('tempData')
} catch (error) {
  console.error('Storage operation failed:', error)
}

Storage Management

javascript
// Check storage usage
wx.getStorageInfo({
  success: (res) => {
    const usage = (res.currentSize / res.limitSize * 100).toFixed(1)
    console.log(`Storage: ${usage}% used (${res.currentSize}KB/${res.limitSize}KB)`)
    console.log('Keys:', res.keys)
  }
})

// Clean up storage
function cleanupStorage() {
  const info = wx.getStorageInfoSync()
  if (info.currentSize > info.limitSize * 0.8) { // 80% threshold
    // Remove old cache data
    wx.removeStorageSync('cache')
    wx.removeStorageSync('tempData')
  }
}

Data Organization

Structured Storage

javascript
// Organize data by purpose
const StorageKeys = {
  USER: 'user_profile',
  SETTINGS: 'app_settings',
  CACHE: 'data_cache',
  TEMP: 'temp_data'
}

// User data structure
const userData = {
  profile: {
    id: '12345',
    name: 'John Doe',
    avatar: 'https://example.com/avatar.jpg'
  },
  preferences: {
    theme: 'dark',
    language: 'en',
    notifications: true
  },
  metadata: {
    lastLogin: Date.now(),
    version: '1.0.0'
  }
}

wx.setStorageSync(StorageKeys.USER, userData)

Data Validation

javascript
function validateAndStore(key, data) {
  try {
    // Validate data before storing
    if (!data || typeof data !== 'object') {
      throw new Error('Invalid data format')
    }
    
    // Add metadata
    const dataWithMeta = {
      data: data,
      timestamp: Date.now(),
      version: '1.0'
    }
    
    wx.setStorageSync(key, dataWithMeta)
    return true
  } catch (error) {
    console.error('Storage validation failed:', error)
    return false
  }
}

function validateAndRetrieve(key) {
  try {
    const stored = wx.getStorageSync(key)
    if (!stored || !stored.data) {
      return null
    }
    
    // Check if data is too old (e.g., 7 days)
    const maxAge = 7 * 24 * 60 * 60 * 1000 // 7 days in milliseconds
    if (Date.now() - stored.timestamp > maxAge) {
      wx.removeStorageSync(key)
      return null
    }
    
    return stored.data
  } catch (error) {
    console.error('Storage retrieval failed:', error)
    return null
  }
}

3. Storage Management

javascript
class StorageManager {
  constructor() {
    this.maxSize = 10 * 1024 // 10MB limit
    this.cleanupThreshold = 0.8 // Clean up when 80% full
  }
  
  set(key, data, options = {}) {
    try {
      const { expiry, priority = 'normal' } = options
      
      const item = {
        data,
        timestamp: Date.now(),
        expiry: expiry ? Date.now() + expiry : null,
        priority,
        size: JSON.stringify(data).length
      }
      
      // Check storage space
      this.checkAndCleanup()
      
      wx.setStorageSync(key, item)
      this.updateIndex(key, item)
      
      return true
    } catch (error) {
      console.error('Failed to store data:', error)
      return false
    }
  }
  
  get(key) {
    try {
      const item = wx.getStorageSync(key)
      if (!item) return null
      
      // Check expiry
      if (item.expiry && Date.now() > item.expiry) {
        this.remove(key)
        return null
      }
      
      return item.data
    } catch (error) {
      console.error('Failed to retrieve data:', error)
      return null
    }
  }
  
  remove(key) {
    try {
      wx.removeStorageSync(key)
      this.removeFromIndex(key)
      return true
    } catch (error) {
      console.error('Failed to remove data:', error)
      return false
    }
  }
  
  checkAndCleanup() {
    const info = wx.getStorageInfoSync()
    const usageRatio = info.currentSize / info.limitSize
    
    if (usageRatio > this.cleanupThreshold) {
      this.cleanup()
    }
  }
  
  cleanup() {
    const index = this.getIndex()
    const now = Date.now()
    
    // Remove expired items first
    Object.keys(index).forEach(key => {
      const item = index[key]
      if (item.expiry && now > item.expiry) {
        this.remove(key)
      }
    })
    
    // If still over threshold, remove low priority items
    const info = wx.getStorageInfoSync()
    if (info.currentSize / info.limitSize > this.cleanupThreshold) {
      this.removeLowPriorityItems()
    }
  }
  
  updateIndex(key, item) {
    const index = this.getIndex()
    index[key] = {
      timestamp: item.timestamp,
      expiry: item.expiry,
      priority: item.priority,
      size: item.size
    }
    wx.setStorageSync('_storage_index', index)
  }
  
  getIndex() {
    return wx.getStorageSync('_storage_index') || {}
  }
}

// Usage
const storage = new StorageManager()

// Store data with expiry (1 hour)
storage.set('tempData', { value: 'temporary' }, { 
  expiry: 60 * 60 * 1000,
  priority: 'low'
})

// Store important data
storage.set('userProfile', userProfile, { priority: 'high' })

Cloud Storage

For data that needs to be synchronized across devices or shared between users, consider using cloud storage solutions.

WeChat Cloud Development

javascript
// Initialize cloud
wx.cloud.init({
  env: 'your-env-id'
})

// Store data in cloud database
const db = wx.cloud.database()

// Add data
db.collection('users').add({
  data: {
    name: 'John Doe',
    email: 'john@example.com',
    createdAt: new Date()
  }
}).then(res => {
  console.log('Data added to cloud:', res._id)
}).catch(error => {
  console.error('Failed to add data:', error)
})

// Query data
db.collection('users').where({
  name: 'John Doe'
}).get().then(res => {
  console.log('Query result:', res.data)
}).catch(error => {
  console.error('Query failed:', error)
})

// Update data
db.collection('users').doc('user-id').update({
  data: {
    email: 'newemail@example.com',
    updatedAt: new Date()
  }
}).then(res => {
  console.log('Data updated:', res)
}).catch(error => {
  console.error('Update failed:', error)
})

File Storage

javascript
// Upload file to cloud storage
wx.cloud.uploadFile({
  cloudPath: 'images/avatar.jpg',
  filePath: tempFilePath,
}).then(res => {
  console.log('File uploaded:', res.fileID)
  
  // Store file reference in local storage
  wx.setStorageSync('avatarFileID', res.fileID)
}).catch(error => {
  console.error('Upload failed:', error)
})

// Download file from cloud storage
wx.cloud.downloadFile({
  fileID: 'cloud://env-id.file-id',
}).then(res => {
  console.log('File downloaded:', res.tempFilePath)
}).catch(error => {
  console.error('Download failed:', error)
})

Data Synchronization

Offline-First Strategy

javascript
class DataSync {
  constructor() {
    this.syncQueue = []
    this.isOnline = true
    
    // Monitor network status
    wx.onNetworkStatusChange((res) => {
      this.isOnline = res.isConnected
      if (this.isOnline) {
        this.processSyncQueue()
      }
    })
  }
  
  async saveData(key, data, syncToCloud = true) {
    // Always save locally first
    wx.setStorageSync(key, {
      data,
      timestamp: Date.now(),
      synced: false
    })
    
    if (syncToCloud) {
      if (this.isOnline) {
        await this.syncToCloud(key, data)
      } else {
        this.addToSyncQueue(key, data)
      }
    }
  }
  
  async syncToCloud(key, data) {
    try {
      // Sync to cloud storage
      await wx.cloud.database().collection('userData').add({
        data: {
          key,
          data,
          timestamp: Date.now()
        }
      })
      
      // Mark as synced
      const localData = wx.getStorageSync(key)
      localData.synced = true
      wx.setStorageSync(key, localData)
      
    } catch (error) {
      console.error('Sync to cloud failed:', error)
      this.addToSyncQueue(key, data)
    }
  }
  
  addToSyncQueue(key, data) {
    this.syncQueue.push({ key, data, timestamp: Date.now() })
    wx.setStorageSync('syncQueue', this.syncQueue)
  }
  
  async processSyncQueue() {
    const queue = wx.getStorageSync('syncQueue') || []
    
    for (const item of queue) {
      try {
        await this.syncToCloud(item.key, item.data)
        // Remove from queue after successful sync
        this.syncQueue = this.syncQueue.filter(q => q !== item)
      } catch (error) {
        console.error('Failed to sync queued item:', error)
        break // Stop processing if sync fails
      }
    }
    
    wx.setStorageSync('syncQueue', this.syncQueue)
  }
}

Security Considerations

Data Encryption

javascript
// Simple encryption utility (for demonstration)
class SecureStorage {
  constructor(secretKey) {
    this.secretKey = secretKey
  }
  
  encrypt(data) {
    // In production, use a proper encryption library
    const jsonString = JSON.stringify(data)
    const encrypted = btoa(jsonString) // Base64 encoding (not secure)
    return encrypted
  }
  
  decrypt(encryptedData) {
    try {
      const decrypted = atob(encryptedData) // Base64 decoding
      return JSON.parse(decrypted)
    } catch (error) {
      console.error('Decryption failed:', error)
      return null
    }
  }
  
  setSecure(key, data) {
    const encrypted = this.encrypt(data)
    wx.setStorageSync(key, encrypted)
  }
  
  getSecure(key) {
    const encrypted = wx.getStorageSync(key)
    if (!encrypted) return null
    return this.decrypt(encrypted)
  }
}

// Usage
const secureStorage = new SecureStorage('your-secret-key')
secureStorage.setSecure('sensitiveData', { token: 'abc123' })
const data = secureStorage.getSecure('sensitiveData')

Data Validation

javascript
function validateUserData(data) {
  const schema = {
    name: { type: 'string', required: true, maxLength: 50 },
    email: { type: 'string', required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
    age: { type: 'number', min: 0, max: 150 }
  }
  
  for (const [key, rules] of Object.entries(schema)) {
    const value = data[key]
    
    if (rules.required && (value === undefined || value === null)) {
      throw new Error(`${key} is required`)
    }
    
    if (value !== undefined) {
      if (rules.type && typeof value !== rules.type) {
        throw new Error(`${key} must be of type ${rules.type}`)
      }
      
      if (rules.maxLength && value.length > rules.maxLength) {
        throw new Error(`${key} exceeds maximum length`)
      }
      
      if (rules.pattern && !rules.pattern.test(value)) {
        throw new Error(`${key} format is invalid`)
      }
      
      if (rules.min !== undefined && value < rules.min) {
        throw new Error(`${key} is below minimum value`)
      }
      
      if (rules.max !== undefined && value > rules.max) {
        throw new Error(`${key} exceeds maximum value`)
      }
    }
  }
  
  return true
}

Performance Optimization

Lazy Loading

javascript
class LazyDataLoader {
  constructor() {
    this.cache = new Map()
    this.loadingPromises = new Map()
  }
  
  async getData(key, loader) {
    // Return cached data if available
    if (this.cache.has(key)) {
      return this.cache.get(key)
    }
    
    // Return existing loading promise if already loading
    if (this.loadingPromises.has(key)) {
      return this.loadingPromises.get(key)
    }
    
    // Start loading
    const loadingPromise = this.loadData(key, loader)
    this.loadingPromises.set(key, loadingPromise)
    
    try {
      const data = await loadingPromise
      this.cache.set(key, data)
      return data
    } finally {
      this.loadingPromises.delete(key)
    }
  }
  
  async loadData(key, loader) {
    // Try to load from local storage first
    const localData = wx.getStorageSync(key)
    if (localData && this.isDataFresh(localData)) {
      return localData.data
    }
    
    // Load from remote source
    const data = await loader()
    
    // Cache locally
    wx.setStorageSync(key, {
      data,
      timestamp: Date.now()
    })
    
    return data
  }
  
  isDataFresh(localData, maxAge = 5 * 60 * 1000) { // 5 minutes
    return Date.now() - localData.timestamp < maxAge
  }
}

Testing Storage

javascript
// Storage testing utilities
class StorageTest {
  static async testStorageCapacity() {
    const testData = 'x'.repeat(1024) // 1KB of data
    let count = 0
    
    try {
      while (true) {
        wx.setStorageSync(`test_${count}`, testData)
        count++
        
        if (count % 100 === 0) {
          console.log(`Stored ${count}KB of data`)
        }
      }
    } catch (error) {
      console.log(`Storage limit reached at approximately ${count}KB`)
      
      // Clean up test data
      for (let i = 0; i < count; i++) {
        wx.removeStorageSync(`test_${i}`)
      }
    }
  }
  
  static testStoragePerformance() {
    const testData = { name: 'Test', value: Math.random() }
    const iterations = 1000
    
    // Test write performance
    const writeStart = Date.now()
    for (let i = 0; i < iterations; i++) {
      wx.setStorageSync(`perf_test_${i}`, testData)
    }
    const writeTime = Date.now() - writeStart
    
    // Test read performance
    const readStart = Date.now()
    for (let i = 0; i < iterations; i++) {
      wx.getStorageSync(`perf_test_${i}`)
    }
    const readTime = Date.now() - readStart
    
    console.log(`Write performance: ${writeTime}ms for ${iterations} operations`)
    console.log(`Read performance: ${readTime}ms for ${iterations} operations`)
    
    // Clean up
    for (let i = 0; i < iterations; i++) {
      wx.removeStorageSync(`perf_test_${i}`)
    }
  }
}

Best Practices Summary

  1. Use Appropriate Storage Type:

    • Local storage for user preferences and cached data
    • Cloud storage for data that needs synchronization
    • Session storage for temporary data
  2. Implement Data Validation:

    • Validate data before storing
    • Handle storage errors gracefully
    • Use schemas for complex data structures
  3. Manage Storage Space:

    • Monitor storage usage
    • Implement cleanup strategies
    • Use data compression when appropriate
  4. Ensure Data Security:

    • Encrypt sensitive data
    • Validate data integrity
    • Never store passwords or tokens in plain text
  5. Optimize Performance:

    • Use lazy loading for large datasets
    • Implement caching strategies
    • Batch storage operations when possible
  6. Plan for Offline Scenarios:

    • Implement offline-first strategies
    • Queue operations for later synchronization
    • Provide meaningful feedback to users

Next Steps

Now that you understand data storage in mini programs, you can explore:

Connecting Multiple Platforms, Empowering Innovation