Cron jobs are scheduled tasks that run at predefined times or intervals. In this tutorial, we’ll explore how to set up Cron jobs in a NextJS application to delete inactive user accounts using Prisma as our ORM (Object-Relational Mapping) tool with PostgreSQL as the database.
Understanding Cron
Cron is an abbreviation of ‘ Chronicle’,
which refers to the chronological order in which jobs are scheduled. It’s a daemon (background service) that runs continuously, checking for jobs to execute based on predefined schedules.
Cron jobs use a specific syntax to define when and how often a command or script should run. The basic syntax is as follows:
* * * * * command to be executed
- - - - -
| | | | |
| | | | +----- day of the week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of the month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)
Special characters can be used to define specific time intervals:
-
*
: Any value -
,
: Separate multiple values (e.g.,1,5,10
) -
-
: Range of values (e.g.,1-5
) -
/
: Skip values (e.g.,*/5
means every 5 minutes)
You can use crontab to create your Cron jobs and see how much time it will run. This makes it easier to navigate the expressions.
Getting Started
For this tutorial, I am hosting my project on Vercel, and I will be following their guidelines on creating a Cron job.
Vercel makes it incredibly simple to run scheduled functions using their built-in Cron Jobs feature. You don't need an external scheduler — Vercel handles the triggering of your scheduled functions for you.
To create a Cron job on Vercel, you need to define a serverless function and then schedule it using the vercel.json
configuration file or through the Vercel dashboard.
Step 1: Create a New API Route
Start by creating a new file under the /api
directory in your Next.js app. This route will contain the code that will be executed when the Cron job runs, which in our case is the logic to delete inactive users.
// /api/cron/permanent-delete-users.ts
import { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "@/lib/prisma";
export default async function handler(
req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}
const THRESHOLD_DAYS = 30;
//delete users who are inactive for more than 30 days
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - THRESHOLD_DAYS);
try {
const deletedUsers = await prisma.user.deleteMany({
where: {
deletedAt: {
lte: cutoffDate, //less than or equal to
},
},
});
return res.status(200).json({
message: `Permanently deleted ${deletedUsers.count}
users whose deletedAt was more than
${THRESHOLD_DAYS} days ago.`,
});
} catch (error) {
console.error("Error during permanent deletion:", error);
return res.status(500).json({ message: "Internal server error" });
}
}
Step 2: Add the Cron Job to vercel.json
Vercel knows about the cron jobs by checking the vercel.json
file, which follows a specific pattern based on what day and time you selected. In this case, we want this function to run every day at 2 AM.
{
"crons": [
{
"path": "/api/cron/delete-inactive-users",
"schedule": "0 2 * * *" // Every day at 2:00 AM UTC,
"headers": {
"x-cron-secret": "@cron_secret"
}
}
]
}
This configuration tells Vercel to send a POST request to /api/cron/delete-inactive-users
Every day at 2:00 AM UTC.
Step 3: Soft Deleting Users
The whole purpose of the Cron job is that users can delete their accounts and then call to ask why their account was deleted. This approach allows us to soft delete user records and allows them to recover their account within 30 days. We should also send users an email with the recovery link that would last for the stipulated days. Here is what happens when users delete their account.
await prisma.user.update({
where: { id: userId },
data: {
deletedAt: new Date(),
},
});
// SendAccountDeletionEmail() here
Step 4: Securing and Managing Your Cron
As you might have guessed this looks spooky and super unsafe since anyone could hit this route and delete user accounts. Vercel allows users to secure their Cron routes by setting a CRON_SECRET
That will be sent with each request.
We need to update our route as follows:
// set chron secret
CRON_SECRET = "your-token"
//api/cron/permanent-delete-users.ts
import type { NextRequest, NextResponse } from 'next/server';
export function POST(req: NextRequest, res: NextResponse) {
const authHeader = req.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', {
status: 401,
});
}
// rest of the function
}
We can also protect this route using a middleware that intercepts the request and checks for authentication, but this is not a good idea since Vercel is managing the service.
Conclusion
Setting up Cron jobs in a Next.js application using Vercel, Prisma, and PostgreSQL is a powerful way to automate routine backend tasks like data cleanup. In this tutorial, we built a scheduled task to permanently delete user accounts that were soft-deleted more than 30 days ago — helping you maintain a lean and healthy database.
Tech Wizard
Published on