General
Background Tasks

Vercel Workflows

Integrate Vercel Workflows with your application for serverless background tasks.

Vercel Workflows is a serverless workflow orchestration platform that lets you build reliable, long-running background tasks directly on Vercel's infrastructure. It's perfect for applications already deployed on Vercel.

Setup

Vercel Workflows is available as part of your Vercel deployment. To get started:

  1. Ensure your project is deployed on Vercel
  2. Install the Vercel Workflows SDK:
Terminal
npm install @vercel/workflows

Configure environment variables

Add your Vercel Workflows credentials to your environment variables:

.env
VERCEL_WORKFLOWS_SECRET=your_workflows_secret_here

You can find this in your Vercel dashboard under your project settings.

Create your first workflow

Create workflows in a workflows directory:

workflows/process-user-data.ts
import { workflow } from '@vercel/workflows';

export const processUserData = workflow(
  'process-user-data',
  async (input: {
    userId: string;
    operation: 'export' | 'analyze' | 'cleanup';
  }) => {
    const { userId, operation } = input;

    console.log('Starting user data processing', { userId, operation });

    switch (operation) {
      case 'export':
        // Export user data
        await new Promise((resolve) => setTimeout(resolve, 2000));
        console.log('User data exported successfully');
        return { success: true, result: 'Data exported to CSV' };

      case 'analyze':
        // Analyze user data
        await new Promise((resolve) => setTimeout(resolve, 5000));
        console.log('User data analysis completed');
        return {
          success: true,
          result: { totalActions: 156, avgSessionTime: '4m 32s' }
        };

      case 'cleanup':
        // Cleanup user data
        await new Promise((resolve) => setTimeout(resolve, 3000));
        console.log('User data cleanup completed');
        return { success: true, result: 'Removed 23 obsolete records' };

      default:
        throw new Error(`Unknown operation: ${operation}`);
    }
  }
);

Create a scheduled workflow:

workflows/daily-cleanup.ts
import { schedule, workflow } from '@vercel/workflows';

export const dailyCleanup = workflow('daily-cleanup', async () => {
  console.log('Starting daily cleanup');

  // Cleanup old logs
  await new Promise((resolve) => setTimeout(resolve, 5000));
  console.log('Logs cleaned up');

  // Cleanup temporary files
  await new Promise((resolve) => setTimeout(resolve, 3000));
  console.log('Temp files cleaned up');

  // Generate daily reports
  await new Promise((resolve) => setTimeout(resolve, 8000));
  console.log('Reports generated');

  return {
    success: true,
    cleanupTime: new Date().toISOString(),
    itemsProcessed: 1247
  };
});

// Schedule the workflow to run daily at 2 AM
schedule(dailyCleanup, {
  cron: '0 2 * * *'
});

Triggering workflows

From an API route

app/api/tasks/process-user-data/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getWorkflowClient } from '@vercel/workflows';
import * as z from 'zod';

import { getSession } from '@/lib/auth/server';

const processUserDataSchema = z.object({
  userId: z.string(),
  operation: z.enum(['export', 'analyze', 'cleanup'])
});

export async function POST(request: NextRequest) {
  const session = await getSession();

  if (!session) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json();
  const { userId, operation } = processUserDataSchema.parse(body);

  const client = getWorkflowClient();

  const handle = await client.trigger('process-user-data', {
    userId,
    operation
  });

  return NextResponse.json({
    success: true,
    workflowId: handle.id,
    message: 'Background task started successfully'
  });
}

From a server action

app/actions/user-actions.ts
'use server';

import { getWorkflowClient } from '@vercel/workflows';

import { getSession } from '@/lib/auth/server';

export async function processUserData(
  userId: string,
  operation: 'export' | 'analyze' | 'cleanup'
) {
  const session = await getSession();

  if (!session) {
    throw new Error('Unauthorized');
  }

  try {
    const client = getWorkflowClient();
    const handle = await client.trigger('process-user-data', {
      userId,
      operation
    });

    return {
      success: true,
      workflowId: handle.id
    };
  } catch (error) {
    console.error('Failed to trigger background task:', error);
    throw new Error('Failed to start background task');
  }
}

Monitoring and debugging

Visit the Vercel Dashboard to monitor your workflows:

  • View workflow execution logs and performance metrics
  • Track success and failure rates
  • Monitor workflow duration
  • Replay failed workflows
  • Set up alerts for workflow failures

Best practices

Use descriptive workflow IDs

// ✅ Good
workflow('user-data-export-csv', async () => {});

// ❌ Not so good
workflow('task1', async () => {});

Handle errors gracefully

workflow('process-data', async (input) => {
  try {
    return await processData(input);
  } catch (error) {
    console.error('Processing failed:', error);
    throw error; // Re-throw to trigger retry
  }
});

Use structured logging

console.log('Workflow started', {
  workflowId: 'process-user-data',
  userId: input.userId,
  operation: input.operation,
  timestamp: new Date().toISOString()
});

Next steps

With Vercel Workflows integrated into your application, you can now:

  • Handle long-running operations that would timeout in serverless functions
  • Schedule recurring tasks like reports, cleanups, and maintenance
  • Process background jobs reliably with automatic retries
  • Monitor workflows directly in your Vercel dashboard

Ready to explore more? Check out the official documentation for advanced features like workflow composition, event triggers, and more.