v0 + Bolt.new: Full-Stack Development Hands-On Tutorial
Learn how to use v0 and Bolt.new to quickly build full-stack web applications, from design to deployment in one go.
Introduction
v0 and Bolt.new are two revolutionary AI development tools:
- v0: Vercel's product, focused on UI component generation
- Bolt.new: Full-stack application generator, create complete projects with one command
Today we'll use them to build a task management app from scratch.
Step 1: Design UI with v0
Open v0.dev and input:
Create a modern task management app UI with:
- Top navigation (logo, search, user avatar)
- Left sidebar (project list, tag filters)
- Main content (task card list with drag-sort)
- Right detail panel (task details, subtasks, comments)
- Tailwind CSS and shadcn/ui components
- Dark mode support
v0 generates a complete UI design with all interaction details.
Generated Component Example
// TaskCard component
export function TaskCard({ task }: { task: Task }) {
return (
<Card className="group cursor-pointer hover:shadow-md transition-shadow">
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<Badge variant={task.priority === 'high' ? 'destructive' : 'secondary'}>
{task.priority}
</Badge>
<Button variant="ghost" size="icon" className="opacity-0 group-hover:opacity-100">
<MoreHorizontal className="h-4 w-4" />
</Button>
</div>
</CardHeader>
<CardContent>
<h3 className="font-semibold">{task.title}</h3>
<p className="text-sm text-muted-foreground mt-1">{task.description}</p>
<div className="flex items-center gap-2 mt-4">
<Avatar className="h-6 w-6">
<AvatarImage src={task.assignee.avatar} />
</Avatar>
<span className="text-xs text-muted-foreground">{task.dueDate}</span>
</div>
</CardContent>
</Card>
);
}
Step 2: Build Backend with Bolt.new
Open bolt.new and input:
Create a task management app backend using:
- Next.js 14 App Router
- Prisma + PostgreSQL
- NextAuth.js authentication
- RESTful API
Features:
- User registration/login
- Task CRUD (title, description, priority, due date, status)
- Project management (project contains multiple tasks)
- Task comments
- Assign tasks to team members
Generated API Example
// app/api/tasks/route.ts
import { prisma } from '@/lib/prisma';
import { auth } from '@/auth';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const session = await auth();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { searchParams } = new URL(request.url);
const projectId = searchParams.get('projectId');
const tasks = await prisma.task.findMany({
where: {
projectId: projectId || undefined,
project: {
members: {
some: { userId: session.user.id }
}
}
},
include: {
assignee: true,
comments: { take: 5 },
},
orderBy: { createdAt: 'desc' },
});
return NextResponse.json(tasks);
}
export async function POST(request: Request) {
const session = await auth();
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const body = await request.json();
const task = await prisma.task.create({
data: {
title: body.title,
description: body.description,
priority: body.priority,
dueDate: body.dueDate,
projectId: body.projectId,
createdById: session.user.id,
},
});
return NextResponse.json(task, { status: 201 });
}
Step 3: Integrate Frontend and Backend
1. Integrate v0 Components
# Copy v0 generated components
cp -r v0-components/* src/components/
2. Connect API
// hooks/useTasks.ts
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then(res => res.json());
export function useTasks(projectId?: string) {
const { data, error, mutate } = useSWR(
`/api/tasks${projectId ? `?projectId=${projectId}` : ''}`,
fetcher
);
const createTask = async (task: CreateTaskInput) => {
const res = await fetch('/api/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(task),
});
const newTask = await res.json();
mutate([...data, newTask]);
return newTask;
};
return {
tasks: data,
isLoading: !error && !data,
error,
createTask,
};
}
3. Assemble Page
// app/dashboard/page.tsx
'use client';
import { Sidebar } from '@/components/Sidebar';
import { TaskBoard } from '@/components/TaskBoard';
import { TaskDetail } from '@/components/TaskDetail';
import { useTasks } from '@/hooks/useTasks';
export default function DashboardPage() {
const { tasks, isLoading, createTask } = useTasks();
const [selectedTask, setSelectedTask] = useState(null);
if (isLoading) return <LoadingSpinner />;
return (
<div className="flex h-screen">
<Sidebar />
<TaskBoard
tasks={tasks}
onTaskClick={setSelectedTask}
onCreateTask={createTask}
/>
{selectedTask && (
<TaskDetail
task={selectedTask}
onClose={() => setSelectedTask(null)}
/>
)}
</div>
);
}
Step 4: Deploy
One-Click Vercel Deployment
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Set environment variables
vercel env add DATABASE_URL
vercel env add NEXTAUTH_SECRET
Complete Project Structure
my-task-app/
├── app/
│ ├── api/
│ │ ├── tasks/
│ │ ├── projects/
│ │ └── auth/
│ ├── dashboard/
│ └── layout.tsx
├── components/
│ ├── ui/ # shadcn/ui components
│ ├── TaskCard.tsx # v0 generated
│ ├── TaskBoard.tsx # v0 generated
│ └── Sidebar.tsx # v0 generated
├── hooks/
├── lib/
│ └── prisma.ts
└── prisma/
└── schema.prisma
Development Time Comparison
| Traditional | AI-Assisted | |------------|------------| | UI Design: 2 days | v0: 30 mins | | Backend API: 3 days | Bolt.new: 1 hour | | Integration/Debug: 2 days | Manual: half day | | Total: 7 days | Total: 1 day |
Important Notes
- Review AI-generated code: Check for security and business logic
- Iterate gradually: Don't generate everything at once, validate step by step
- Maintain consistency: Ensure v0 and Bolt use the same tech stack
Summary
The v0 + Bolt.new combination makes full-stack development unprecedented efficient. From idea to launch might only take a day.
Next: Prompt Engineering Tips - Learn to write better AI instructions