Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

Caching

Intelligent caching that improves performance automatically. Simple TTL-based caching with dynamic keys and automatic invalidation.

Caching That Just Works

Add caching to any route with one line.
Automatic TTL management, dynamic keys, and smart invalidation.

It's This Simple

Add caching with one line

typescript

1app.get('/users')
2  .cache({ ttl: 60 }) // Cache for 60 seconds
3  .handler(() => {
4    // This only runs if not cached
5    return getAllUsers();
6  });

Why Caching Matters

Without caching, every request hits your database or expensive operations. With caching, responses are instant.

Traditional caching requires manual setup, key management, and invalidation logic. We handle that automatically.

Without Caching

  • Every request hits the database
  • Slow response times
  • High server load
  • Manual cache management

With MoroJS

  • Instant responses from cache
  • Reduced database load
  • Automatic TTL management
  • One-line setup

It's This Easy

Add caching to any route. That's it.

Dynamic cache keys with parameters

typescript

1app.get('/users/:id')
2  .cache({ 
3    ttl: 300, // 5 minutes
4    key: (req) => `user-${req.params.id}`
5  })
6  .handler(({ params }) => {
7    return getUserById(params.id);
8  });

Why It Makes Sense

Fast

Instant responses from cache. No database queries for cached data.

Automatic

TTL-based expiration. No manual cache management needed.

Simple

One line of code. Dynamic keys. Smart invalidation.

How It Works

MoroJS caching automatically stores responses based on cache keys and TTL (time-to-live) values. When a request comes in, it checks the cache first. If found, it returns immediately. If not, it executes the handler and stores the result.

Route-Level Caching

Basic Route Caching

typescript

1import { createApp, z } from '@morojs/moro';
2
3const app = createApp();
4
5// Simple caching with TTL
6app.get('/users')
7  .query(z.object({
8    limit: z.coerce.number().min(1).max(100).default(10),
9    search: z.string().optional()
10  }))
11  .cache({ ttl: 60, key: 'users-list' }) // Cache for 60 seconds
12  .handler((req, res) => {
13    // This will only run if not cached
14    const users = getAllUsers(req.query);
15    return { success: true, data: users };
16  });
17
18// Dynamic cache keys with parameters
19app.get('/users/:id')
20  .cache({ ttl: 300, key: (req) => `user-${req.params.id}` }) // 5 minutes
21  .handler((req, res) => {
22    const user = getUserById(req.params.id);
23    return { success: true, data: user };
24  });

Different TTLs for Different Data

typescript

1// Fast-changing data - short cache
2app.get('/data/fast')
3  .cache({ ttl: 30 }) // 30 seconds
4  .handler(() => getFastChangingData());
5
6// Stable data - long cache
7app.get('/data/slow')
8  .cache({ ttl: 3600 }) // 1 hour
9  .handler(() => getSlowChangingData());

Advanced Caching

For advanced use cases, you can integrate external caching solutions like Redis, implement tag-based invalidation, and manage cache manually.

Tag-Based Invalidation

typescript

1import { getCache } from '@morojs/moro';
2
3app.post('/users', {
4  body: CreateUserSchema,
5  handler: async ({ body }) => {
6    const user = await createUser(body);
7    
8    // Invalidate user-related caches
9    const cache = getCache();
10    await cache.invalidateByTag(['users']);
11    
12    return { user };
13  }
14});

Manual Cache Management

typescript

1import { getCache } from '@morojs/moro';
2
3const cache = getCache();
4
5// Set cache manually
6await cache.set('key', { data: 'value' }, { ttl: '1h' });
7
8// Get from cache
9const cached = await cache.get('key');
10
11// Delete specific key
12await cache.delete('key');
13
14// Get cache stats
15const stats = await cache.getStats();
16console.log(`Hit rate: ${stats.hitRate}%`);

Next Steps