Advanced
Performance Tuning
Optimize your MoroJS applications for maximum performance. Learn caching strategies, database optimization, and monitoring techniques for production workloads.
Overview
Optimize your application with built-in caching, compression, and monitoring. Database optimization and query monitoring included.
1import { createApp } from '@morojs/moro';
2
3const app = await createApp({
4 cors: true,
5 compression: true, // Built-in performance feature
6 helmet: true
7});
8
9// Built-in caching with chainable API
10app.get('/users')
11 .cache({ ttl: 60, key: 'users-list' }) // Cache for 60 seconds
12 .handler((req, res) => {
13 const users = getAllUsers(req.query);
14 return { success: true, data: users };
15 });Without proper optimization, you're wasting resources, slowing down responses, and increasing costs. With MoroJS, you get caching, compression, and monitoring automatically.
Traditional performance optimization requires manual setup. We handle that automatically.
Without Optimization
- Slow response times
- No caching
- No performance monitoring
- Higher server costs
With MoroJS
- Fast response times
- Built-in caching
- Performance monitoring
- Lower server costs
Fast
Built-in caching and compression for optimal performance
Monitored
Performance monitoring and slow query detection
Optimized
Database query optimization and connection pooling
How It Works
MoroJS provides built-in performance features including caching, compression, and monitoring. You can enable caching per route, monitor query performance, and optimize database connections with minimal configuration.
Performance Monitoring
1import { createApp } from '@morojs/moro';
2
3const app = await createApp({
4 cors: true,
5 compression: true, // Built-in performance feature
6 helmet: true
7});
8
9// Simple performance middleware (custom implementation)
10app.use((req, res, next) => {
11 const start = Date.now();
12
13 // Add request timing
14 req.startTime = start;
15
16 // Override res.json to add timing header
17 const originalJson = res.json;
18 res.json = function(data) {
19 const duration = Date.now() - start;
20 res.setHeader('X-Response-Time', `${duration}ms`);
21
22 // Log slow requests
23 if (duration > 1000) {
24 console.warn(`Slow request: ${req.method} ${req.path} - ${duration}ms`);
25 }
26
27 return originalJson.call(this, data);
28 };
29
30 next();
31});
32
33// Health check with performance metrics
34app.get('/health', (req, res) => {
35 const memUsage = process.memoryUsage();
36
37 return {
38 status: 'healthy',
39 timestamp: new Date().toISOString(),
40 uptime: process.uptime(),
41 memory: {
42 rss: Math.round(memUsage.rss / 1024 / 1024) + 'MB',
43 heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024) + 'MB',
44 heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024) + 'MB'
45 },
46 nodeVersion: process.version
47 };
48});Advanced Caching Strategies
1// Built-in caching with chainable API (actual implementation)
2app.get('/users')
3 .query(z.object({
4 limit: z.coerce.number().default(10),
5 search: z.string().optional()
6 }))
7 .cache({ ttl: 60, key: 'users-list' }) // Cache for 60 seconds
8 .handler((req, res) => {
9 const users = getAllUsers(req.query);
10 return { success: true, data: users };
11 });
12
13// Dynamic cache keys
14app.get('/users/:id')
15 .cache({ ttl: 300, key: (req) => `user-${req.params.id}` }) // 5 minutes
16 .handler((req, res) => {
17 const user = getUserById(req.params.id);
18 return { success: true, data: user };
19 });
20
21// Configuration-driven caching
22app.get('/data')
23 .cache({ ttl: app.getConfig().modules.cache.defaultTtl })
24 .handler((req, res) => {
25 return { data: getExpensiveData() };
26 });
27
28// External Redis caching (for advanced use cases)
29import Redis from 'redis';
30
31const redis = Redis.createClient({ url: process.env.REDIS_URL });
32await redis.connect();
33
34// Custom Redis middleware
35const redisCache = (ttl) => {
36 return async (req, res, next) => {
37 const cacheKey = `cache:${req.method}:${req.path}`;
38
39 try {
40 const cached = await redis.get(cacheKey);
41 if (cached) {
42 res.setHeader('X-Cache', 'HIT');
43 return res.json(JSON.parse(cached));
44 }
45
46 const originalJson = res.json;
47 res.json = function(data) {
48 redis.setEx(cacheKey, ttl, JSON.stringify(data));
49 res.setHeader('X-Cache', 'MISS');
50 return originalJson.call(this, data);
51 };
52
53 next();
54 } catch (error) {
55 console.error('Cache error:', error);
56 next();
57 }
58 };
59};
60
61// Use Redis caching
62app.get('/expensive-data').use(redisCache(300)).handler((req, res) => {
63 const data = performExpensiveOperation();
64 return { success: true, data };
65});Database Optimization
1// Query performance monitoring
2const queryMonitor = {
3 slowQueryThreshold: 1000, // 1 second
4
5 async logSlowQuery(query: string, params: any[], duration: number) {
6 if (duration > this.slowQueryThreshold) {
7 console.warn('Slow query detected:', {
8 query,
9 params,
10 duration: `${duration}ms`,
11 timestamp: new Date().toISOString()
12 });
13
14 // Send to monitoring service
15 await sendMetric('slow_query', {
16 query_hash: hashQuery(query),
17 duration,
18 timestamp: Date.now()
19 });
20 }
21 }
22};
23
24// Optimized database middleware
25app.use(async (context, next) => {
26 const originalQuery = context.db.query;
27
28 context.db.query = async (sql: string, params: any[] = []) => {
29 const start = Date.now();
30
31 try {
32 const result = await originalQuery.call(context.db, sql, params);
33 const duration = Date.now() - start;
34
35 await queryMonitor.logSlowQuery(sql, params, duration);
36
37 return result;
38 } catch (error) {
39 console.error('Database query error:', { sql, params, error: error.message });
40 throw error;
41 }
42 };
43
44 await next();
45});
46
47// Connection pool optimization
48app.get('/users/:id')
49 .handler(async ({ params, db }) => {
50 // Use read replica for read-only queries
51 const user = await db.replica.query(
52 'SELECT id, name, email FROM users WHERE id = $1',
53 [params.id]
54 );
55
56 if (!user[0]) {
57 return { error: 'User not found' };
58 }
59
60 // Use cache for frequently accessed data
61 const cacheKey = `user_profile:${params.id}`;
62 let profile = await cache.get(cacheKey);
63
64 if (!profile) {
65 profile = await db.replica.query(
66 'SELECT bio, avatar_url, preferences FROM user_profiles WHERE user_id = $1',
67 [params.id]
68 );
69
70 await cache.set(cacheKey, profile[0], { ttl: '15m' });
71 }
72
73 return {
74 ...user[0],
75 profile: profile[0]
76 };
77 });