Skip to content

Nitro Cache Invalidation

Overview

The frontend uses Nitro's built-in caching to serve frequently-accessed data faster and reduce backend load. When data changes in the backend, the cache needs to be invalidated.

Cached Endpoints

EndpointCache DurationStale DurationDescription
/api/settings24 hours7 daysSite settings (rarely change)
/api/competitions60 seconds5 minutesPublic competitions list
/api/competitions/featured2 minutes10 minutesFeatured competitions

Cache Invalidation

Site Settings

When site settings are updated in the admin panel, the backend should invalidate the frontend cache:

typescript
// In your backend settings controller (after updating settings)
const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:4000'
const CACHE_SECRET = process.env.CACHE_INVALIDATION_SECRET

try {
  await fetch(`${FRONTEND_URL}/api/cache/invalidate/settings`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${CACHE_SECRET}`
    }
  })
  console.log('Frontend settings cache invalidated successfully')
} catch (error) {
  console.error('Failed to invalidate frontend cache:', error)
  // Non-critical - cache will expire after 24 hours anyway
}

Environment Variables

Backend .env:

bash
FRONTEND_URL=http://localhost:4000  # or https://yourdomain.com in production
CACHE_INVALIDATION_SECRET=your-secret-token-here

Frontend .env:

bash
CACHE_INVALIDATION_SECRET=your-secret-token-here  # Same secret as backend

Generate a secure secret:

bash
# Generate random secret
openssl rand -hex 32

Security

  • The cache invalidation endpoint requires authentication via Bearer token
  • The secret should be strong (32+ characters) and kept confidential
  • Only the backend should have access to this endpoint
  • Invalid requests return 401 Unauthorized

Error Handling

Cache invalidation is non-critical:

  • If invalidation fails, the cache will automatically expire after the TTL (24 hours for settings)
  • The backend should log failures but not block the user's request
  • Use try-catch to handle network errors gracefully

Example Implementation in Backend

File: src/controllers/siteSettingsController.ts

typescript
import { Response } from 'express'
import { AuthRequest } from '../types/auth'

const invalidateFrontendCache = async () => {
  const FRONTEND_URL = process.env.FRONTEND_URL
  const CACHE_SECRET = process.env.CACHE_INVALIDATION_SECRET

  if (!FRONTEND_URL || !CACHE_SECRET) {
    console.warn('Cache invalidation not configured (missing FRONTEND_URL or CACHE_INVALIDATION_SECRET)')
    return
  }

  try {
    const response = await fetch(`${FRONTEND_URL}/api/cache/invalidate/settings`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${CACHE_SECRET}`
      }
    })

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }

    console.info('Frontend settings cache invalidated successfully')
  } catch (error) {
    console.error('Failed to invalidate frontend cache:', error)
    // Non-critical - don't throw, just log
  }
}

export const updateSiteSettings = async (req: AuthRequest, res: Response) => {
  try {
    // ... update settings logic ...

    // Invalidate frontend cache (fire and forget - don't await)
    invalidateFrontendCache().catch(err => {
      console.error('Cache invalidation error:', err)
    })

    res.json({ success: true, data: updatedSettings })
  } catch (error) {
    // ... error handling ...
  }
}

Testing Cache Invalidation

1. Test the cached endpoint:

bash
# First request - hits backend, caches for 24 hours
curl http://localhost:4000/api/settings

# Second request - served from cache (instant)
curl http://localhost:4000/api/settings

2. Test cache invalidation:

bash
# Invalidate the cache
curl -X POST http://localhost:4000/api/cache/invalidate/settings \
  -H "Authorization: Bearer your-secret-token-here"

# Response:
# {"success":true,"message":"Site settings cache invalidated","timestamp":"2025-12-16T13:00:00.000Z"}

3. Verify cache was cleared:

bash
# This should fetch fresh data from backend again
curl http://localhost:4000/api/settings

Monitoring

Cache performance metrics are automatically logged:

  • Cache hits/misses
  • Response times
  • Invalidation requests

Check Nitro logs for cache-related messages:

[Cache Invalidation] Site settings cache cleared successfully
[API Proxy] Failed to fetch site settings: <error>

Best Practices

  1. Always invalidate after updates: Call the invalidation endpoint after any settings change
  2. Don't block on invalidation: Use fire-and-forget pattern (don't await)
  3. Log failures: Cache invalidation failures are non-critical but should be logged
  4. Use environment variables: Never hardcode the secret or URLs
  5. Test in staging: Verify cache invalidation works before deploying to production

Troubleshooting

Cache not invalidating?

  • Check that CACHE_INVALIDATION_SECRET matches in both backend and frontend
  • Verify FRONTEND_URL points to the correct frontend server
  • Check network connectivity between backend and frontend
  • Look for errors in backend logs when calling the invalidation endpoint

401 Unauthorized errors?

  • Verify the secret token is correct
  • Check the Authorization header format: Bearer <token>
  • Ensure the secret is not empty or undefined

Cache still serving stale data?

  • Check if you're testing the right endpoint (/api/settings not ${API_BASE}/settings)
  • Verify the invalidation request succeeded (check response)
  • Clear browser cache if testing in a browser
  • Wait a few seconds for Nitro to finish clearing the cache