V0 projects use Next.js App Router, so favicons go in the /app directory as favicon.ico (auto-detected) and meta tags are set via the metadata export in layout.tsx. Unlike traditional HTML where you manually add link and meta tags to the head, Next.js handles this through its Metadata API, which V0 supports natively in generated projects.
Why favicons and meta tags need special handling in V0 projects
V0 generates Next.js App Router projects where traditional HTML head manipulation does not work. There is no index.html file to edit. Instead, Next.js uses a file-based convention for favicons (placing favicon.ico in /app) and a TypeScript-based Metadata API for title, description, and Open Graph tags. V0 often generates projects without these configured, leaving pages with default Next.js favicons and missing social preview cards.
- Placing favicon.ico in /public instead of /app (App Router convention)
- Trying to add meta tags via a manual <head> element instead of the metadata export
- Missing Open Graph images causing blank social media previews
- V0 not generating metadata exports in layout.tsx by default
- Using generateMetadata in a client component marked with 'use client'
Error messages you might see
You are attempting to export "metadata" from a component marked with "use client", which is unsupported.The metadata or generateMetadata export only works in Server Components. Remove the 'use client' directive from layout.tsx or page.tsx where you define metadata.
Error: "metadata" is not a valid export from "./app/page.tsx". Only "default", "generateMetadata", "generateStaticParams" are allowed.Page-level metadata must use either the static metadata object or the generateMetadata async function. Check that the export name is exactly 'metadata' and the file is a Server Component.
Unsupported metadata property: 'favicon'Next.js Metadata API uses 'icons' not 'favicon' as the property name. Replace metadata.favicon with metadata.icons.
Before you start
- A V0 project using Next.js App Router
- A favicon file in .ico, .png, or .svg format
- Basic understanding of Next.js layout.tsx structure
How to fix it
Add favicon.ico to the /app directory
Next.js App Router auto-detects favicon.ico, apple-icon.png, and icon.png when placed in the /app directory. Placing them in /public requires manual configuration.
Add favicon.ico to the /app directory
Next.js App Router auto-detects favicon.ico, apple-icon.png, and icon.png when placed in the /app directory. Placing them in /public requires manual configuration.
Upload your favicon.ico file to the /app directory in V0's file explorer. For additional icon sizes, add icon.png (32x32) and apple-icon.png (180x180) in the same directory. Next.js generates the appropriate link tags automatically.
// No favicon configured — browser shows default icon// File incorrectly placed at: /public/favicon.ico// Correct placement for App Router auto-detection:// /app/favicon.ico → standard favicon// /app/icon.png → 32x32 PNG icon// /app/apple-icon.png → 180x180 Apple touch iconExpected result: Browser tab displays your custom favicon without any code changes needed.
Export metadata in layout.tsx for site-wide meta tags
The Metadata API in Next.js App Router replaces manual head tag management. Defining metadata in the root layout applies it across all pages, with per-page overrides available.
Export metadata in layout.tsx for site-wide meta tags
The Metadata API in Next.js App Router replaces manual head tag management. Defining metadata in the root layout applies it across all pages, with per-page overrides available.
Open app/layout.tsx in V0's code editor. Add a metadata export with title, description, and Open Graph properties. This must be in a Server Component — do not add 'use client' to this file.
export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body>{children}</body> </html> );}import type { Metadata } from 'next';export const metadata: Metadata = { title: 'My App — Built with V0', description: 'A modern web application built with V0 and Next.js', openGraph: { title: 'My App — Built with V0', description: 'A modern web application built with V0 and Next.js', images: ['/og-image.png'], }, icons: { icon: '/favicon.ico', apple: '/apple-icon.png', },};export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body>{children}</body> </html> );}Expected result: Page title appears in the browser tab, and sharing the URL on social media shows the correct title, description, and preview image.
Add per-page metadata with generateMetadata for dynamic pages
Dynamic routes like /blog/[slug] need unique meta tags per page for SEO. The generateMetadata function runs server-side and can fetch data to build page-specific metadata.
Add per-page metadata with generateMetadata for dynamic pages
Dynamic routes like /blog/[slug] need unique meta tags per page for SEO. The generateMetadata function runs server-side and can fetch data to build page-specific metadata.
In any page.tsx file, export a generateMetadata async function. This function receives the route params and can fetch data to construct dynamic titles and descriptions. It works alongside the root layout metadata — page-level values override layout-level defaults.
// app/blog/[slug]/page.tsxexport default function BlogPost({ params,}: { params: { slug: string };}) { return <article>Blog content</article>;}// app/blog/[slug]/page.tsximport type { Metadata } from 'next';type Props = { params: { slug: string } };export async function generateMetadata( { params }: Props): Promise<Metadata> { const post = await fetch( `https://api.example.com/posts/${params.slug}` ).then((res) => res.json()); return { title: post.title, description: post.excerpt, openGraph: { title: post.title, description: post.excerpt, images: [post.coverImage], }, };}export default function BlogPost({ params }: Props) { return <article>Blog content</article>;}Expected result: Each blog post page has its own unique title, description, and social preview image based on the post data.
Complete code example
1import type { Metadata } from 'next';2import { Inter } from 'next/font/google';3import './globals.css';45const inter = Inter({ subsets: ['latin'] });67export const metadata: Metadata = {8 title: {9 default: 'My V0 App',10 template: '%s | My V0 App',11 },12 description: 'A modern application built with V0 and Next.js',13 metadataBase: new URL('https://my-app.vercel.app'),14 openGraph: {15 title: 'My V0 App',16 description: 'A modern application built with V0 and Next.js',17 url: 'https://my-app.vercel.app',18 siteName: 'My V0 App',19 images: [20 {21 url: '/og-image.png',22 width: 1200,23 height: 630,24 alt: 'My V0 App preview',25 },26 ],27 locale: 'en_US',28 type: 'website',29 },30 twitter: {31 card: 'summary_large_image',32 title: 'My V0 App',33 description: 'A modern application built with V0 and Next.js',34 images: ['/og-image.png'],35 },36 icons: {37 icon: '/favicon.ico',38 apple: '/apple-icon.png',39 },40 robots: {41 index: true,42 follow: true,43 },44};4546export default function RootLayout({47 children,48}: {49 children: React.ReactNode;50}) {51 return (52 <html lang="en">53 <body className={inter.className}>{children}</body>54 </html>55 );56}Best practices to prevent this
- Always place favicon.ico in the /app directory for automatic detection in Next.js App Router projects
- Set metadataBase in your root layout to ensure Open Graph image URLs resolve to absolute paths
- Use the title.template pattern ('%%s | Site Name') in root layout so child pages only need to set a page-specific title
- Never add 'use client' to files that export metadata — the Metadata API only works in Server Components
- Include og-image.png (1200x630px) in your /public folder and reference it in openGraph.images for social sharing
- Test meta tags with the Vercel deployment preview URL before publishing to production
- Use generateMetadata for dynamic routes to ensure each page has unique SEO content
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a V0 Next.js App Router project and need to add a custom favicon and meta tags. The favicon is in /public but the browser shows the default Next.js icon. How do I configure metadata properly using the App Router Metadata API?
Frequently asked questions
Where do I put the favicon.ico file in a V0 Next.js project?
Place favicon.ico directly in the /app directory, not /public. Next.js App Router automatically detects favicon.ico, icon.png, and apple-icon.png when placed in /app and generates the appropriate HTML link tags.
Why does my metadata export cause a build error in V0?
The most common cause is having 'use client' at the top of the file. The metadata and generateMetadata exports only work in Server Components. Remove the 'use client' directive from any file that exports metadata.
How do I add different meta tags to each page in V0?
Export a metadata object or generateMetadata function from each page.tsx file. Page-level metadata overrides root layout metadata. Use generateMetadata for dynamic routes that need to fetch data for titles and descriptions.
Can I add Google Analytics tracking alongside meta tags?
Yes. Use the next/script component with strategy='afterInteractive' for Google Analytics, and the metadata export for meta tags. These are separate systems in Next.js — see the dedicated guide on using Google Analytics in V0 apps.
How do I preview Open Graph tags before deploying?
Deploy to Vercel's preview environment via Share then Publish, then test the preview URL with tools like opengraph.xyz or the Facebook Sharing Debugger. V0's in-editor preview does not render meta tags visually.
Why does my favicon show in V0 preview but not after deploying?
This usually means the favicon is in /public (works in dev) but not in /app (required for production builds in App Router). Move favicon.ico to /app. Also clear your browser cache, as favicons are aggressively cached.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your issue.
Book a free consultation