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.