Nuxt renders pages on the server, so search engines get real HTML instead of an empty shell. That is a great start, but good rankings still need the right meta tags, clean URLs and a sitemap. Here is the checklist I use on every Nuxt 4 project.
1. Set a title and description on every page#
useSeoMeta({
title: 'Projects - Alamgir Hosen',
description: 'Web apps and online stores built with Laravel and Nuxt.',
ogTitle: 'Projects - Alamgir Hosen',
ogDescription: 'Web apps and online stores built with Laravel and Nuxt.',
ogImage: '/og-image.png',
twitterCard: 'summary_large_image'
})
Keep titles under 60 characters and descriptions under 160, and make each one unique.
2. Load page data on the server#
Use useFetch or useAsyncData at the top of the page, not inside onMounted. Data fetched only in the browser is invisible to crawlers.
3. Add a canonical URL#
useHead({
link: [{ rel: 'canonical', href: `https://example.com${useRoute().path}` }]
})
This stops filters and tracking parameters from creating duplicate pages.
4. Generate a sitemap#
The @nuxtjs/sitemap module builds /sitemap.xml from your routes. For dynamic pages like articles, feed it the URLs from your API.
5. Return real 404s#
When an item is not found, throw an error so the server answers with status 404 instead of an empty page with status 200:
if (!article.value) {
throw createError({ statusCode: 404, statusMessage: 'Article not found', fatal: true })
}
6. Add structured data#
JSON-LD helps Google understand your content and can show richer results:
useHead({
script: [{
type: 'application/ld+json',
innerHTML: JSON.stringify({ '@context': 'https://schema.org', '@type': 'Article', headline: article.value.title })
}]
})
7. Keep it fast#
- Use
<NuxtImg>with width and height to avoid layout shift. - Preload the main heading font.
- Lazy-load images below the fold.
Check every page with Google Search Console after launch. It shows which pages are indexed and why others are not.




