Intermediate25 minModule 4 of 4

Ship It

Deploy your AI Image Studio to production — environment variables, Vercel deployment, webhook configuration, and monitoring.

Pre-deployment checklist

Before deploying, verify these are in place:

  • API key stored in environment variable, not in source code
  • Webhook secret set and verified in the handler
  • CDN output URLs downloaded and persisted to Blob storage
  • Database migrations applied (npx prisma db push)
  • CORS headers configured for your domain
  • Error states handled in the UI

Deploy to Vercel

# Install Vercel CLI
npm i -g vercel

# Deploy (first run creates the project)
vercel

# Or deploy straight to production
vercel --prod

Environment variables in Vercel

In the Vercel dashboard, go to Settings → Environment Variables and add:

VariableValueEnvironments
SKYTELLS_API_KEYsk-prod-...Production only
SKYTELLS_WEBHOOK_SECRETFrom Skytells APIProduction only
DATABASE_URLYour Postgres URLAll
BLOB_READ_WRITE_TOKENFrom Vercel BlobAll
NEXT_PUBLIC_APP_URLhttps://yourapp.vercel.appProduction

Set separate SKYTELLS_API_KEY values for preview and production environments.

Configure the webhook URL

Skytells does not require pre-registering webhook URLs in the Console. Instead, pass your endpoint URL in the webhook field when creating a prediction:

{
  "model": "truefusion-pro",
  "input": { "prompt": "..." },
  "webhook": "https://yourapp.vercel.app/api/webhooks"
}

Skytells will POST the completed prediction payload to your endpoint once processing finishes. Obtain your webhook signing secret from the Skytells API (see the API reference) and set it as SKYTELLS_WEBHOOK_SECRET in Vercel.

Database setup (Neon / Supabase)

Both Neon and Supabase offer free-tier Postgres with direct connection strings:

# After setting DATABASE_URL in Vercel environment
npx prisma db push

For connection pooling in a serverless environment:

DATABASE_URL="postgresql://...?pgbouncer=true&connection_limit=1"

Testing webhooks locally

Use the Skytells webhook testing tool or a forwarding service during development:

# Using ngrok
ngrok http 3000

# Then set in .env.local:
NEXT_PUBLIC_APP_URL=https://your-id.ngrok.io

Or test the webhook handler directly with a curl:

PAYLOAD='{"id":"pred_test","status":"succeeded","output":["https://cdn.skytells.ai/test.png"]}'
SIG=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SKYTELLS_WEBHOOK_SECRET" | cut -d' ' -f2)

curl -X POST http://localhost:3000/api/webhooks \
  -H "Content-Type: application/json" \
  -H "x-skytells-signature: sha256=$SIG" \
  -d "$PAYLOAD"

Monitoring

Track key metrics

// lib/analytics.ts
export function trackGeneration(event: {
  predictionId: string;
  model: string;
  status: 'created' | 'succeeded' | 'failed';
  latencyMs?: number;
}) {
  // Send to your analytics (Posthog, Mixpanel, etc.)
  console.log('[generation]', event);
}

Vercel's built-in observability

Enable Vercel Analytics and Speed Insights in your project settings — both are free for hobby tier and give you:

  • Request latency per route
  • Error rate by route
  • Real user performance data

Budget guardrails

Set spending limits in the Console → Settings → Billing to prevent unexpected charges during load testing or after a traffic spike.

Rate limiting

Add rate limiting to your generate endpoint to protect against abuse:

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

const REQUESTS_PER_MINUTE = 5;
const requestCounts = new Map<string, { count: number; resetAt: number }>();

export function middleware(req: NextRequest) {
  if (!req.nextUrl.pathname.startsWith('/api/generate')) {
    return NextResponse.next();
  }

  const ip = req.headers.get('x-forwarded-for') ?? 'unknown';
  const now = Date.now();
  const entry = requestCounts.get(ip);

  if (!entry || entry.resetAt < now) {
    requestCounts.set(ip, { count: 1, resetAt: now + 60_000 });
    return NextResponse.next();
  }

  if (entry.count >= REQUESTS_PER_MINUTE) {
    return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
  }

  entry.count++;
  return NextResponse.next();
}

What to build next

Now that your Image Studio is live, here are natural extensions:

FeatureComplexityImpact
User authentication (Clerk)LowHigh — enables personalized history
Prompt suggestions / examplesLowMedium — reduces blank canvas
Image variations (img2img)MediumHigh — power user feature
Public galleryMediumHigh — viral / social
Inpainting / editingHighHigh — differentiator
Subscription billing (Stripe)MediumHigh — monetization

Congratulations

You've built and shipped a production AI Image Studio. Along the way you learned:

  1. Architecture planning before writing code
  2. Backend: prediction creation, webhook handling, persistent storage
  3. Frontend: optimistic UI, real-time polling, component composition
  4. Production: deployment, environment config, monitoring

Next paths:

On this page