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 API | 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
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 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 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:
| 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