upstash logo

Optimizing Vercel Functions With Upstash Workflow

This demo shows the cost-saving benefits of using Upstash Workflow for Vercel functions. It compares two methods of calling an image generation API:

Both methods start at the same time and take about the same time to finish. The key difference is the estimated cost per 1M requests (hover for details).

Prompt: A futuristic city skyline at dusk, with towering skyscrapers and flying vehicles in the style of retro sci-fi art. Colors should feature deep purples, bright neon pinks, and glowing electric blues.

Traditional Serverless Function
Total Duration0ms
Vercel Function Duration0ms
Cost for 1M Requests~$0
Vercel Function
import { NextRequest, NextResponse } from 'next/server'
import { ImageResponse } from 'utils/types'

export const POST = async (request: NextRequest) => {
  // get prompt from request
  const params = await request.json()
  const prompt = params.prompt as string

  // make the fetch request
  const response = await fetch(
    "https://api.ideogram.ai/generate",
    {
      method: "POST",
      body: JSON.stringify({
        image_request: {
          model: 'V_2',
          prompt,
          aspect_ratio: 'ASPECT_1_1',
          magic_prompt_option: 'AUTO',
        },
      }),
      headers: {
        'Content-Type': 'application/json',
        'Api-Key': process.env.IDEOGRAM_API_KEY!
      },
    }
  )

  // get the image url
  const payload = await response.json() as ImageResponse
  const url = payload.data[0].url

  return new NextResponse(
    JSON.stringify({ url }),
    { status: 200 }
  )
}
Serverless Function with Upstash Workflow
Total Duration0ms
Vercel Function Duration0ms
Cost for 1M Requests~$0
Workflow Function
import { serve } from "@upstash/qstash/nextjs"
import { Redis } from "@upstash/redis"
import { ImageResponse } from "utils/types"

const redis = Redis.fromEnv()

export const POST = serve<{ prompt: string }>(
  async (context) => {
    // get prompt from request
    const { prompt } = context.requestPayload

    // make the call to Idogram through QStash
    const result = await context.call<ImageResponse>(
      'call Ideogram',
      "https://api.ideogram.ai/generate",
      "POST",
      {
        image_request: {
          model: 'V_2',
          prompt,
          aspect_ratio: 'ASPECT_1_1',
          magic_prompt_option: 'AUTO',
        },
      },
      {
        'Content-Type': 'application/json',
        'Api-Key': process.env.IDEOGRAM_API_KEY!,
      },
    )

    // save the image url in redis
    // so that UI can access it
    await context.run(
      'save results in redis',
      async () => {
        await redis.set<string>(
          context.headers.get('callKey')!,
          result.data[0].url,
          { ex: 120 }, // expire in 120 seconds
        )
      }
    )
  }
)