Back to Blog
tips9 min read

Technical SEO for Next.js Applications: Core Web Vitals and Beyond

Technical SEO implementation for Next.js — Metadata API, structured data, Core Web Vitals, sitemaps, and performance budgets.

V
By Ventra Rocket
·Published on 10 January 2026
#SEO#Next.js#Core Web Vitals#Performance#Structured Data

Technical SEO determines whether search engines can discover and rank your content. Next.js App Router makes SEO cleaner, but requires deliberate implementation.

1. Metadata API

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const post = await getPost(params.slug);
  return {
    title: `${post.title} | Ventra Rocket Blog`,
    description: post.excerpt,
    alternates: {
      canonical: `https://ventrarocket.vn/en/blogs/${post.slug}`,
      languages: {
        vi: `https://ventrarocket.vn/vi/blogs/${post.slug}`,
        en: `https://ventrarocket.vn/en/blogs/${post.slug}`,
      },
    },
    openGraph: {
      type: "article",
      title: post.title,
      description: post.excerpt,
      publishedTime: post.date,
      images: [{ url: post.coverImage, width: 1200, height: 630 }],
    },
  };
}

2. Structured Data (JSON-LD)

function ArticleJsonLd({ post, locale }: Props) {
  const schema = {
    "@context": "https://schema.org",
    "@type": "TechArticle",
    headline: post.title,
    author: { "@type": "Organization", name: "Ventra Rocket" },
    datePublished: post.date,
    inLanguage: locale,
    keywords: post.tags.join(", "),
  };
  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
    />
  );
}

3. Sitemap Generation

// app/sitemap.ts
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const slugs = getBlogSlugs();
  const locales = ["vi", "en"];

  return [
    { url: "https://ventrarocket.vn", priority: 1, changeFrequency: "daily" },
    ...locales.flatMap((locale) =>
      slugs.map((slug) => ({
        url: `https://ventrarocket.vn/${locale}/blogs/${slug}`,
        lastModified: new Date(),
        changeFrequency: "weekly" as const,
        priority: 0.7,
      }))
    ),
  ];
}

4. Core Web Vitals

LCP < 2.5s — Use priority on above-fold images:

<Image src="/hero.webp" alt="Hero" priority width={1200} height={600} />

CLS < 0.1 — Always specify image dimensions, never omit width/height.

INP < 200ms — Defer heavy work to idle time:

useEffect(() => {
  const id = requestIdleCallback(() => expensiveComputation());
  return () => cancelIdleCallback(id);
}, []);

5. Performance Budget in CI

// lighthouserc.js
module.exports = {
  ci: {
    assert: {
      assertions: {
        "categories:performance": ["error", { minScore: 0.85 }],
        "categories:seo": ["error", { minScore: 0.95 }],
        "largest-contentful-paint": ["error", { maxNumericValue: 2500 }],
        "cumulative-layout-shift": ["error", { maxNumericValue: 0.1 }],
      },
    },
  },
};

Conclusion

Technical SEO: metadata, JSON-LD, sitemaps, Core Web Vitals, performance budgets in CI. Ventra Rocket websites consistently score 90+ on PageSpeed Insights.

Related Articles

Technical SEO for Next.js Applications: Core Web Vitals and Beyond | Ventra Rocket