DEV Community

Cover image for Setting up Redis in a Next.js Application
Hadiza Mohammed
Hadiza Mohammed

Posted on

Setting up Redis in a Next.js Application

In modern web development, performance matters. Users expect pages to load instantly and real-time features to work seamlessly. This is where Redis comes in an in-memory data store known for blazing-fast performance and scalability. Redis is perfect for use cases like caching, session management, rate limiting, and storing temporary data such as OTP codes or pending appointments.

In this article, we’ll walk you through how to integrate Redis into a Next.js application, covering both server-side logic and practical use cases like caching and session storage. We’ll be using Upstash Redis, a serverless Redis service that works perfectly with Vercel and other platforms.

Why Use Redis in a Next.js App?

Here are some key scenarios where Redis can boost the performance of your Next.js application:

  • Session Management: Store and retrieve user sessions, including access tokens.
  • Caching: Speed up page loading by caching frequently requested data.
  • Rate Limiting: Prevent abuse by limiting the number of API requests from a user.
  • Temporary Data: Store OTPs, appointment statuses, or tokens with expiration times.
  • Real-time Data: Use Redis’s Pub/Sub feature to send real-time updates to users.

Getting Started

Step 1: Set up a Next.js Application
If you don’t already have a Next.js project, let’s create one:

npx create-next-app@latest redis-next-app
cd redis-next-app

Step 2: Install the Redis Client for Upstash
We’ll use the Upstash Redis package, a serverless Redis solution designed for serverless platforms.

npm install @upstash/redis

Step 3: Get Redis Credentials from Upstash

  1. Go to Upstash and create an account.
  2. Create a new Redis database.
  3. Copy the Redis URL and Access Token from the dashboard.

Step 4: Store Redis Credentials in Environment Variables
Create a .env.local file in your project root and add the following:

REDIS_URL=<your-redis-url>
REDIS_TOKEN=<your-redis-token>

Make sure to never hardcode credentials in your code—using environment variables keeps them secure.

Setting Up Redis in Your Next.js App

Let’s create a Redis client that can be reused across the entire application.


// lib/redis.ts
import { Redis } from '@upstash/redis';

// Initialize Redis using credentials from environment variables
const redis = new Redis({
  url: process.env.REDIS_URL!,
  token: process.env.REDIS_TOKEN!,
});

export default redis;

Enter fullscreen mode Exit fullscreen mode

Now we can import this Redis client in our API routes or server components.

Use Case 1: Caching API Responses
Imagine you’re fetching data from a slow external API. Let’s use Redis to cache the API response and speed things up for future requests.

// pages/api/cache-example.ts
import { NextApiRequest, NextApiResponse } from 'next';
import redis from '@/lib/redis';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const cacheKey = 'myApiData';

  // Try to retrieve data from Redis cache
  const cachedData = await redis.get(cacheKey);
  if (cachedData) {
    console.log('Serving from cache');
    return res.status(200).json(JSON.parse(cachedData));
  }

  // If not in cache, fetch from an external API (simulate with static data)
  const data = { message: 'Hello from an external API' };

  // Store the result in Redis with a TTL (time-to-live) of 1 hour
  await redis.setex(cacheKey, 3600, JSON.stringify(data));

  res.status(200).json(data);
}
Enter fullscreen mode Exit fullscreen mode

Try hitting the endpoint:

http://localhost:3000/api/cache-example

On the first request, data will be fetched from the API. On subsequent requests, Redis will serve the cached version.

Use Case 2: Storing and Validating OTP Codes
Let’s say we want to store OTP codes for user authentication. Redis is perfect because it supports data expiration.

// pages/api/sendOtp.ts
import redis from '@/lib/redis';
import { randomBytes } from 'crypto';

export default async function handler(req, res) {
  const { email } = req.body;

  // Generate a random OTP
  const otp = randomBytes(3).toString('hex'); // e.g., 'f1a2b3'

  // Store OTP in Redis with a 5-minute expiration
  await redis.setex(`otp:${email}`, 300, otp);

  // Simulate sending OTP via email (just log it for now)
  console.log(`Sending OTP ${otp} to ${email}`);

  res.status(200).json({ message: 'OTP sent' });
}
Enter fullscreen mode Exit fullscreen mode

Validate the OTP:

// pages/api/verifyOtp.ts
import redis from '@/lib/redis';

export default async function handler(req, res) {
  const { email, otp } = req.body;

  // Retrieve OTP from Redis
  const storedOtp = await redis.get(`otp:${email}`);

  if (storedOtp === otp) {
    return res.status(200).json({ message: 'OTP verified' });
  }

  res.status(400).json({ message: 'Invalid OTP' });
}
Enter fullscreen mode Exit fullscreen mode

Use Case 3: Rate Limiting API Requests
To prevent abuse, let’s build a rate limiter that restricts each user to 10 API requests per minute.


// middleware/rateLimiter.ts
import redis from '@/lib/redis';
import { NextRequest, NextResponse } from 'next/server';

export default async function middleware(req: NextRequest) {
  const ip = req.ip ?? 'unknown';

  const requests = await redis.incr(ip); // Increment request count
  if (requests === 1) {
    await redis.expire(ip, 60); // Set expiration to 1 minute
  }

  if (requests > 10) {
    return NextResponse.json({ message: 'Rate limit exceeded' }, { status: 429 });
  }

  return NextResponse.next(); // Proceed if within the limit
}
Enter fullscreen mode Exit fullscreen mode

Add this middleware to specific routes using the Next.js config.

Conclusion

Integrating Redis with Next.js can drastically improve your app's performance by caching data, managing sessions, and storing temporary information. In this guide, we explored:

How to set up Redis in a Next.js project.
Using Redis for caching, OTP management and rate limiting.
Happy coding! 🚀

Top comments (0)