Add AI Images to Next.js — Code Guide
Integrate DALL-E 3 into your Next.js app in 10 minutes. Complete code examples included. Free API key to start.
How to Add AI Image Generation to Your Next.js App (With Code)
Adding AI image generation to your Next.js app is easier than you think. In this guide, we'll build a complete image generator component with DALL-E 3 integration.
What We'll Build
A Next.js app that:
- Generates images from text prompts
- Displays generated images
- Handles loading states and errors
- Saves images to user's account
- Works with both App Router and Pages Router
Prerequisites
- Next.js project (App Router or Pages Router)
- Imagify API key (get one free)
- Basic React knowledge
Step 1: Set Up Your Next.js Project
If you don't have a Next.js project yet:
npx create-next-app@latest ai-image-generator
cd ai-image-generator
Step 2: Install Dependencies
npm install axios
Step 3: Create API Route (App Router)
Create app/api/generate/route.ts:
import { NextRequest, NextResponse } from 'next/server';
import axios from 'axios';
export async function POST(request: NextRequest) {
try {
const { prompt, size, style } = await request.json();
const apiKey = process.env.IMAGIFY_API_KEY;
if (!apiKey) {
return NextResponse.json(
{ error: 'API key not configured' },
{ status: 500 }
);
}
const response = await axios.post(
'https://api.imagify.ca/api/images/generate',
{
prompt,
size: size || '1024x1024',
style: style || 'standard'
},
{
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
}
);
return NextResponse.json(response.data);
} catch (error: any) {
console.error('Image generation error:', error);
return NextResponse.json(
{ error: error.response?.data?.error || 'Failed to generate image' },
{ status: error.response?.status || 500 }
);
}
}
Step 4: Create API Route (Pages Router)
If using Pages Router, create pages/api/generate.ts:
import type { NextApiRequest, NextApiResponse } from 'next';
import axios from 'axios';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { prompt, size, style } = req.body;
const apiKey = process.env.IMAGIFY_API_KEY;
if (!apiKey) {
return res.status(500).json({ error: 'API key not configured' });
}
const response = await axios.post(
'https://api.imagify.ca/api/images/generate',
{
prompt,
size: size || '1024x1024',
style: style || 'standard'
},
{
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
}
);
res.status(200).json(response.data);
} catch (error: any) {
console.error('Image generation error:', error);
res.status(error.response?.status || 500).json({
error: error.response?.data?.error || 'Failed to generate image'
});
}
}
Step 5: Create Image Generator Component
Create components/ImageGenerator.tsx:
'use client';
import { useState } from 'react';
import axios from 'axios';
interface GeneratedImage {
id: string;
url: string;
prompt: string;
}
export default function ImageGenerator() {
const [prompt, setPrompt] = useState('');
const [size, setSize] = useState('1024x1024');
const [style, setStyle] = useState('standard');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [images, setImages] = useState<GeneratedImage[]>([]);
const handleGenerate = async (e: React.FormEvent) => {
e.preventDefault();
if (!prompt.trim()) {
setError('Please enter a prompt');
return;
}
setLoading(true);
setError(null);
try {
const response = await axios.post('/api/generate', {
prompt,
size,
style
});
const newImage: GeneratedImage = {
id: response.data.id || Date.now().toString(),
url: response.data.url,
prompt
};
setImages([newImage, ...images]);
setPrompt('');
} catch (err: any) {
setError(err.response?.data?.error || 'Failed to generate image');
} finally {
setLoading(false);
}
};
return (
<div className="max-w-4xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">AI Image Generator</h1>
<form onSubmit={handleGenerate} className="mb-8">
<div className="mb-4">
<label htmlFor="prompt" className="block text-sm font-medium mb-2">
Image Prompt
</label>
<textarea
id="prompt"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="A futuristic city at sunset with neon lights..."
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
rows={3}
required
/>
</div>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<label htmlFor="size" className="block text-sm font-medium mb-2">
Size
</label>
<select
id="size"
value={size}
onChange={(e) => setSize(e.target.value)}
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="1024x1024">Square (1024x1024)</option>
<option value="1792x1024">Landscape (1792x1024)</option>
<option value="1024x1792">Portrait (1024x1792)</option>
</select>
</div>
<div>
<label htmlFor="style" className="block text-sm font-medium mb-2">
Style
</label>
<select
id="style"
value={style}
onChange={(e) => setStyle(e.target.value)}
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="standard">Standard</option>
<option value="vivid">Vivid</option>
</select>
</div>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Generating...' : 'Generate Image'}
</button>
</form>
{error && (
<div className="mb-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
{error}
</div>
)}
{loading && (
<div className="text-center py-8">
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
<p className="mt-2 text-gray-600">Generating your image...</p>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{images.map((image) => (
<div key={image.id} className="border rounded-lg overflow-hidden">
<img
src={image.url}
alt={image.prompt}
className="w-full h-auto"
/>
<div className="p-4 bg-gray-50">
<p className="text-sm text-gray-600">{image.prompt}</p>
<a
href={image.url}
download
className="mt-2 inline-block text-blue-600 hover:underline text-sm"
>
Download
</a>
</div>
</div>
))}
</div>
</div>
);
}
Step 6: Add Environment Variable
Create or update .env.local:
IMAGIFY_API_KEY=your_api_key_here
Get your API key from Imagify dashboard.
Step 7: Use the Component
App Router
In app/page.tsx:
import ImageGenerator from '@/components/ImageGenerator';
export default function Home() {
return <ImageGenerator />;
}
Pages Router
In pages/index.tsx:
import ImageGenerator from '../components/ImageGenerator';
export default function Home() {
return <ImageGenerator />;
}
Step 8: Add User Authentication (Optional)
To save images to user accounts, add authentication:
// In your API route, add user authentication
const userId = await getUserId(request); // Your auth logic
// Include userId in generation request
const response = await axios.post(
'https://api.imagify.ca/api/images/generate',
{
prompt,
size,
style,
userId // If your API supports it
},
// ... rest of code
);
Advanced Features
Image History
Store generated images in localStorage or database:
useEffect(() => {
const saved = localStorage.getItem('generatedImages');
if (saved) {
setImages(JSON.parse(saved));
}
}, []);
useEffect(() => {
if (images.length > 0) {
localStorage.setItem('generatedImages', JSON.stringify(images));
}
}, [images]);
Image Sharing
Add share functionality:
const handleShare = async (imageUrl: string) => {
if (navigator.share) {
await navigator.share({
title: 'Check out this AI-generated image!',
url: imageUrl
});
} else {
// Fallback: copy to clipboard
await navigator.clipboard.writeText(imageUrl);
alert('Image URL copied to clipboard!');
}
};
Batch Generation
Generate multiple images at once:
const handleBatchGenerate = async (prompts: string[]) => {
setLoading(true);
const results = await Promise.all(
prompts.map(prompt =>
axios.post('/api/generate', { prompt, size, style })
)
);
setImages([...results.map(r => r.data), ...images]);
setLoading(false);
};
Error Handling
Add retry logic:
const generateWithRetry = async (retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
return await axios.post('/api/generate', { prompt, size, style });
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
};
Styling with Tailwind CSS
The component uses Tailwind classes. Make sure Tailwind is configured in your Next.js project.
Deployment
1. Set environment variable in your hosting platform
2. Deploy your Next.js app
3. Test the image generation
Security Considerations
- Never expose API key in client-side code
- Use API routes to keep keys server-side
- Rate limit requests to prevent abuse
- Validate inputs before sending to API
Conclusion
You now have a fully functional AI image generator in your Next.js app! The component handles generation, display, errors, and can be extended with authentication, history, and sharing features.
Get your free API key from Imagify and start generating images in your Next.js app today!
Ready to Start Generating Images?
Get started with free credits and begin creating amazing AI-generated images today.
Get Started Free