Last month, I was staring at a Figma mockup from our design team, dreading the process of turning it into a responsive React component. The design had a complex card layout with hover states, a filtering sidebar, and a data table that needed to sort and paginate. Normally, this would eat up two days of my week. Instead, I opened v0 by Vercel and had a working prototype in twenty minutes.
I was skeptical at first—I've been burned by code generation tools that produce unmaintainable spaghetti. But v0 surprised me. It doesn't just spit out generic HTML; it generates clean, modern React code using Tailwind CSS and shadcn/ui components. Let me walk you through exactly how I use it, including the bumps I hit along the way.
Getting Started: The Prompt Matters More Than You Think
Head over to v0.dev and sign in with your GitHub or Vercel account. You'll land on a chat interface with a prompt box at the bottom. This is where the magic happens.
My first mistake was being too vague. I typed: "Make a dashboard."
v0 generated a generic admin dashboard. It looked fine, but it wasn't what I needed. The layout was basic, the cards were placeholder content, and nothing matched our brand. I quickly learned that specificity is everything.
Here's the prompt that actually got me useful results:
Create a project management dashboard with:
- A sidebar with navigation links (Dashboard, Projects, Team, Settings)
- A main content area with 4 stat cards showing: Active Projects (12),
Completed Tasks (48), Team Members (8), Hours Logged (156)
- A data table below showing recent projects with columns:
Name, Status (badge), Assignee, Due Date, Progress (progress bar)
- Use a dark theme with blue accent colors
- Make it responsive - sidebar collapses on mobile
The difference was night and day. v0 produced a fully interactive dashboard with working state management, responsive breakpoints, and proper Tailwind classes.
Iterating on Generated Code
The real power of v0 isn't the first generation—it's the iteration. After my dashboard appeared, I noticed the sidebar didn't have an active state indicator. Instead of regenerating everything, I just told v0:
Add a blue left border and light blue background to the active
navigation item in the sidebar. Default to "Dashboard" being active.
v0 updated only the relevant code, keeping everything else intact. This conversational workflow is where it shines. I found myself treating it like a pair programmer: "make this wider," "add a loading skeleton state," "the mobile menu isn't closing when I click a link."
One surprise: v0 sometimes rewrites more code than necessary during iterations. If I asked to change a button color, it might regenerate the entire component. I learned to be explicit: "Only modify the button className, keep the rest of the component unchanged."
Working with Real Data and APIs
Static prototypes are nice, but I needed real data. I wanted to connect a contact form to a database. Here's what I prompted:
Create a contact form with name, email, and message fields.
On submit, send a POST request to /api/contact with the form data.
Show a success toast notification on completion and handle errors
with an error state.
v0 generated the form with proper validation, a fetch call, and toast notifications using sonner (a shadcn/ui-compatible toast library). It even included loading states on the submit button.
For a blog project, I wanted to connect to Contentful. I prompted:
Integrate Contentful API to render my blog posts using the "post"
content type with "title", "content" (with Markdown support), and
creation date. Use CONTENTFUL_ACCESS_TOKEN for the API key
and CONTENTFUL_SPACE_ID for the space ID.
v0 set up the Contentful SDK, created the proper types, and rendered Markdown content using a parser. It knew to use environment variables instead of hardcoding keys. I was genuinely impressed—it understood the Contentful content model structure without me explaining it.
Moving Code to Your Project
Once you're happy with the generated code, you need to get it into your actual project. v0 gives you a few options.
The simplest: click "Copy Code" on any generated component and paste it into your project. But this means you need to install dependencies manually (Tailwind, shadcn/ui components, etc.).
The better option: click "Add to Codebase." v0 gives you an npx command that looks something like this:
npx v0 add [component-id]
Running this in your project directory scaffolds the component, installs dependencies, and sets up the file structure. I tried this with a Next.js project and it worked cleanly—though I'd already initialized shadcn/ui, which probably helped.
Heads up: The npx command works best with Next.js projects since v0 generates React/Next code by default. If you're using a different framework like Nuxt or SvelteKit, you'll need to adapt the code manually.
Debugging and Fixing Issues
v0 isn't perfect. I hit a bug where a generated API route was throwing a 500 error when fetching from an external API. Instead of scratching my head for an hour, I pasted the error message and the route code directly into v0:
This Next.js API route is throwing a 500 error when fetching data
from an external API. Here's the code:
[pasted code]
And here's the error:
[pasted error]
Help me debug this.
v0 identified that I wasn't handling the case where the API returned a non-200 status code, and the JSON parsing was failing on the error response. It rewrote the route with proper error handling and try/catch blocks.
I also used it to optimize a component that was re-rendering excessively:
This React component re-renders too often. The filteredList
recalculates on every render even when filters haven't changed.
Optimize it.
v0 wrapped the expensive computation in useMemo and explained why it made the change. It felt like a code review from a senior developer.
GitHub Integration
v0 now connects directly to GitHub. You can push generated code straight to a repository, which is handy for quickly spinning up new projects. I used this to create a prototype, pushed it to a repo, and shared the Vercel preview URL with my team—all without leaving the browser.
For deployment, anything you build in v0 can be deployed directly to Vercel with custom subdomains. This is seamless if you're already in the Vercel ecosystem. If you're on AWS or Netlify, you'll need to go the GitHub route and deploy from there.
Practical Tips and Honest Limitations
After using v0 extensively, here's what I've learned:
Do:
- Be painfully specific in your prompts. Include layout details, color preferences, data structures, and interaction behaviors.
- Iterate in small steps. Generate the base, then refine piece by piece.
- Paste in existing code when asking for modifications. v0 works better with context.
- Use it for prototyping and first drafts, not final production code.
- Take advantage of its Next.js 15 knowledge—it's up to date on the latest features and can help with migrations.
Don't:
- Expect pixel-perfect implementations of complex designs. You'll still need to tweak spacing and polish details.
- Trust generated API routes blindly. Always review security—authentication, input validation, rate limiting.
- Use it for complex backend logic. v0 shines on frontend and full-stack glue code, not intricate business logic.
- Skip understanding the code it generates. You'll need to maintain this code eventually.
Limitations I've hit:
- Complex animations are hit or miss. Simple transitions work; intricate choreographed sequences don't.
- It sometimes generates outdated patterns, like using
useStatefor form state when React Hook Form would be better. - The context window has limits. In long conversations, v0 forgets earlier decisions. I've started new chats when iterations get stale.
- Generated code assumes shadcn/ui and Tailwind. If your project uses different component libraries or CSS approaches, you'll need to translate.
v0 has genuinely changed how I approach frontend work. I use it for first drafts, quick prototypes, and debugging help. It handles the boilerplate and lets me focus on the interesting problems. But it's a tool, not a replacement—understanding what it generates and why is what separates useful output from technical debt.