Skip to main content

Overview

Stringboot’s caching system is designed for maximum performance while minimizing memory usage and network bandwidth. It uses a sophisticated three-layer architecture that automatically manages cache invalidation, eviction, and synchronization.

Cache Lookup Flow

When your application requests a string, Stringboot checks three layers in sequence:

Application Request

Your app calls StringProvider.get("key")

Layer 1: In-Memory LRU Cache

Fastest access: <1ms
  • Size: 1000 entries (configurable)
  • Frequency-based prioritization
  • Returns immediately if found
If cache miss → Check Layer 2

Layer 2: Local Database

Fast persistent storage: 5-20ms
  • Web
  • Android
  • iOS
IndexedDB
  • Persistent across app restarts
  • Automatically synced with memory cache
If not found → Fetch from Network

Layer 3: Network Fetch

Network request: 100-500ms
  • String-Sync v2 Protocol
  • ETag-based conditional requests
  • Delta sync (only changed strings)
  • Result cached in Layers 1 & 2 for future requests
99% of requests are served from Layer 1 (memory) with sub-millisecond latency after initial sync

Layer 1: In-Memory Cache

LRU with Access Frequency

The memory cache uses a Least Recently Used (LRU) algorithm enhanced with access frequency tracking:
  • How It Works
  • Configuration
  • Performance
String Access Pattern:
"welcome_message" → 150 accesses → HIGH PRIORITY → Stays in cache
"error_msg_rare" → 2 accesses → LOW PRIORITY → Evicted first
"logout_confirm" → 50 accesses → MEDIUM PRIORITY → Evicted second
Eviction Logic:
  1. When cache is full (>1000 entries by default)
  2. Calculate score: recentAccess * 0.7 + totalAccess * 0.3
  3. Evict lowest-scoring entries
  4. Keep frequently and recently accessed strings

Cache Statistics

Monitor cache health with statistics:
const stats = await StringBoot.getCacheStats();

console.log({
  memorySize: stats.memory.size,        // 342
  memoryMax: stats.memory.maxSize,      // 1000
  hitRate: (stats.hitRate * 100) + '%', // 94.2%
  dbStrings: stats.db.totalStrings      // 1250
});
What the stats mean:
MetricGoodNeeds Attention
Hit Rate>90%<80%
Memory Usage60-80% of max100% full
Evictions<100/min>500/min
If hit rate is low, consider increasing cacheSize or preloading frequently accessed strings.

Layer 2: Persistent Database

Platform-Specific Storage

  • Web - IndexedDB
  • Android - Room
  • iOS - Core Data
Technology: IndexedDB v2Database Name: stringboot_cacheObject Stores:
  • strings - Actual string content
  • metadata - ETags, timestamps, versioning
Storage Limits:
  • Chrome: ~60% of available disk space
  • Firefox: Quota-based, typically 2GB+
  • Safari: 1GB default
Accessing Database:
// Open in DevTools → Application → IndexedDB
// Database: stringboot_cache
// Store: strings

// Clear database programmatically
await StringBoot.forceRefresh();

Soft Deletes

Stringboot uses soft deletes to avoid data loss:
Regular Delete: ❌ Immediate removal from database
Soft Delete: ✓ Marked as deleted, removed on next full sync
Why soft deletes?
  • Prevents accidental data loss
  • Allows for undo operations
  • Maintains referential integrity
  • Enables offline delete queuing
Cleanup:
// Force cleanup of soft-deleted entries
await StringBoot.forceRefresh(); // Clears all and re-downloads

Layer 3: Network Sync

String-Sync v2 Protocol

Stringboot uses a custom protocol for efficient synchronization:

Step 1: Metadata Check (ETag)

GET https://api.stringboot.com/strings/meta?lang=en
Authorization: Bearer YOUR_TOKEN
If-None-Match: "etag-abc123"
Response A: Not Modified (304)
HTTP/1.1 304 Not Modified
ETag: "etag-abc123"
Result: No download needed, cache is current (~2KB transferred) Response B: Modified (200)
HTTP/1.1 200 OK
ETag: "etag-xyz789"
Content-Type: application/json

{
  "etag": "etag-xyz789",
  "changedKeys": ["welcome_message", "app_title"],
  "deletedKeys": ["old_feature_msg"]
}
Result: Download only changed strings

Step 2: Delta Download

GET https://api.stringboot.com/strings/delta?keys=welcome_message,app_title&lang=en
Authorization: Bearer YOUR_TOKEN
Response:
{
  "strings": [
    {
      "key": "welcome_message",
      "value": "Welcome to our app!",
      "lang": "en"
    },
    {
      "key": "app_title",
      "value": "StringBoot Demo",
      "lang": "en"
    }
  ]
}

Bandwidth Comparison

ScenarioTraditionalString-Sync v2Savings
No changes200KB2KB99%
5 strings changed200KB10KB95%
50 strings changed200KB80KB60%
All new (first sync)200KB200KB0%
ETag checks save 99% bandwidth when content hasn’t changed
Delta sync downloads only what’s needed
Typical monthly bandwidth: 50-200KB vs 3-15MB traditional

Cache Invalidation

When Cache is Cleared

  • Automatic
  • Manual
  • On Errors
  1. Memory pressure (mobile) - Automatic cleanup
  2. Storage quota exceeded (web) - Oldest entries removed
  3. Database corruption - Automatic rebuild
  4. SDK upgrade - Migration or reset

Cache Warming

Preload strings for instant access:
// Preload on app start
await StringBoot.initialize({ /* config */ });

// Preload specific language
await StringBoot.changeLanguage('es');
// Strings are cached automatically

Best Practices

Preload on Start

Preload common strings during app initialization for instant access

Monitor Hit Rate

Aim for >90% cache hit rate. Increase cacheSize if needed.

Don't Force Refresh

Avoid forceRefresh() unless user explicitly requests it

Use Delta Sync

Let SDK handle ETag checks automatically - saves 99% bandwidth

Clear on Logout

Clear cache when user logs out if strings are user-specific

Test Offline

Verify app works perfectly with cached data in airplane mode

Advanced: Cache Debugging

Inspect Cache Contents

// Open IndexedDB in Chrome DevTools
// Application tab → IndexedDB → stringboot_cache → strings

// Or programmatically
const stats = await StringBoot.getCacheStats();
console.log('Total cached strings:', stats.db.totalStrings);

Force Cache Rebuild

Sometimes you need to completely rebuild the cache:
// Clear everything and re-sync
await StringBoot.forceRefresh();

// Clear IndexedDB manually
indexedDB.deleteDatabase('stringboot_cache');

Next Steps