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 --prodEnvironment variables in Vercel
In the Vercel dashboard, go to Settings → Environment Variables and add:
| Variable | Value | Environments |
|---|---|---|
SKYTELLS_API_KEY | sk-prod-... | Production only |
SKYTELLS_WEBHOOK_SECRET | From Skytells Dashboard | Production only |
DATABASE_URL | Your Postgres URL | All |
BLOB_READ_WRITE_TOKEN | From Vercel Blob | All |
NEXT_PUBLIC_APP_URL | https://yourapp.vercel.app | Production |
Set separate SKYTELLS_API_KEY values for preview and production environments.
Configure the webhook URL
After deploying, go to the Skytells Dashboard → API Keys → Webhooks and register:
https://yourapp.vercel.app/api/webhooksEvents to subscribe: prediction.completed
Copy the webhook signing secret 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 pushFor 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.ioOr 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 Skytells Dashboard → Billing → Spend Limits 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:
| Feature | Complexity | Impact |
|---|---|---|
| User authentication (Clerk) | Low | High — enables personalized history |
| Prompt suggestions / examples | Low | Medium — reduces blank canvas |
| Image variations (img2img) | Medium | High — power user feature |
| Public gallery | Medium | High — viral / social |
| Inpainting / editing | High | High — differentiator |
| Subscription billing (Stripe) | Medium | High — monetization |
Congratulations
You've built and shipped a production AI Image Studio. Along the way you learned:
- Architecture planning before writing code
- Backend: prediction creation, webhook handling, persistent storage
- Frontend: optimistic UI, real-time polling, component composition
- Production: deployment, environment config, monitoring
Next paths:
- Generative AI Patterns — caching, deduplication, multi-model
- Enterprise & Compliance — security and privacy at scale