🚀 SEO, Performance और Deploy · Lesson 27
Metadata और SEO
Google को page से क्या चाहिए
- Title — नीला link; clicks के लिए सबसे ज़रूरी।
- Description — उसके नीचे का grey text।
- Canonical URL — कौन सा URL "असली" है।
- Structured data — extra details (price, rating, FAQ)।
Static metadata
JSX – export const metadata
// app/courses/page.jsx (EduSite)
export const metadata = {
title: 'All Courses',
description: 'Coding courses in C, Python, Web Development, Next.js, Android and MySQL with fees and duration.',
alternates: { canonical: '/courses' },
}<head> में बना HTML
<title>All Courses | EduSite</title>
<meta name="description" content="Coding courses in C, Python, Web Development, …">
<link rel="canonical" href="https://edusite.in/courses">
Root layout में title templates
JSX – app/layout.jsx
// app/layout.jsx (EduSite)
import { site } from '@/lib/site'
export const metadata = {
metadataBase: new URL(site.url), // makes relative URLs absolute
title: {
default: `${site.name} – ${site.tagline}`, // used when a page sets no title
template: `%s | ${site.name}`, // "All Courses | EduSite"
},
description: site.description,
alternates: { canonical: '/' },
openGraph: { type: 'website', siteName: site.name, locale: 'en_IN' },
twitter: { card: 'summary_large_image' },
robots: { index: true, follow: true },
}
export const viewport = { themeColor: '#4f46e5' }Dynamic pages के लिए generateMetadata
JSX – generateMetadata
// app/courses/[slug]/page.jsx (EduSite)
export async function generateMetadata({ params }) {
const { slug } = await params
const course = getCourse(slug)
if (!course) return { title: 'Course not found' }
return {
title: `${course.title} Course (${course.duration})`,
description: `${course.summary} Fee ${rupees(course.fee)}. Level: ${course.level}.`,
alternates: { canonical: `/courses/${course.slug}` },
openGraph: { images: [course.image] },
}
}/courses/nextjs का बना HTML
<title>Next.js Course (6 weeks) | EduSite</title>
<meta name="description" content="React + Next.js App Router, APIs, database, SEO and deployment. Fee ₹4,499. Level: Intermediate.">
<link rel="canonical" href="https://edusite.in/courses/nextjs">
<meta property="og:image" content="https://edusite.in/images/nextjs.png">
Canonical URLs और metadataBase
एक ही page /courses, /courses?ref=fb और /courses?q= से खुल सकता है। Canonical tag Google को बताता है कौन सा index करना है ताकि ranking न बँटे। metadataBase एक बार set करने पर '/courses' जैसे छोटे paths लिख सकते हैं।
Open Graph और social images
जब कोई आपका link WhatsApp, Facebook या LinkedIn पर share करता है, तो OG image और title दिखते हैं। opengraph-image.jsx नाम की file वह image अपने आप बनाती है।
JSX – app/opengraph-image.jsx
// app/opengraph-image.jsx (EduSite) — generates a 1200×630 PNG
import { ImageResponse } from 'next/og'
import { site } from '@/lib/site'
export const alt = `${site.name} – ${site.tagline}`
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export default function OpengraphImage() {
return new ImageResponse(
(
<div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column',
justifyContent: 'center', padding: 80,
background: 'linear-gradient(135deg,#4f46e5,#0f172a)', color: '#fff' }}>
<div style={{ fontSize: 88, fontWeight: 800 }}>{site.name}</div>
<div style={{ fontSize: 44, marginTop: 16, opacity: 0.9 }}>{site.tagline}</div>
</div>
),
size
)
}JSON-LD structured data
JSX – components/JsonLd.jsx + usage
// components/JsonLd.jsx (EduSite)
export default function JsonLd({ data }) {
return (
<script type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }} />
)
}
// app/courses/[slug]/page.jsx — Course schema
<JsonLd data={{
'@context': 'https://schema.org',
'@type': 'Course',
name: course.title,
description: course.summary,
provider: { '@type': 'Organization', name: site.name, sameAs: site.url },
offers: { '@type': 'Offer', price: course.fee, priceCurrency: 'INR', category: 'Paid' },
}} />
// app/blog/[slug]/page.jsx — BlogPosting schema
<JsonLd data={{
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
datePublished: post.date,
author: { '@type': 'Organization', name: site.name },
}} />Clicks लाने वाले titles लिखना
| ❌ कमज़ोर | ✅ मज़बूत |
|---|---|
| Next.js | Next.js Course (6 weeks) – Fee ₹4,499 | EduSite |
| Blog post 1 | How to Start Coding in 2026: 30-Day Plan for Beginners |
| Contact | Contact Us – Book a Free Demo Class |
Main keyword पहले रखें, कोई number या फ़ायदा जोड़ें, ~60 characters से कम रखें, और ऐसा description लिखें जो click करने की वजह पर खत्म हो।
SEO कैसे check करें
- 1View page source (Ctrl+U) →
, description, canonical check - 2Google Rich Results Test → JSON-LD validate
- 3Lighthouse → SEO score 100 होना चाहिए
- 4Google Search Console → sitemap submit, impressions और CTR देखें
आम गलतियाँ
- हर page पर एक ही title → Google उन्हें बदल देता है और CTR गिरता है।
metadataBasemissing → OG image URLs relative और previews टूटे।- page.jsx पर
'use client'→ metadata export काम करना बंद। - Visible content से मेल न खाने वाला JSON-LD → manual penalty हो सकती है।
सारांश
- Static pages के लिए
metadata, dynamic के लिएgenerateMetadata। - Root layout:
metadataBase+ title template + defaults। - Canonical, OG image और JSON-LD से SEO पूरा होता है।
✅ Practice
हर page को unique title/description दीजिए, course pages में Course JSON-LD जोड़िए और एक URL Google के Rich Results Test में test कीजिए।
अक्सर पूछे जाने वाले प्रश्न (FAQ)
क्या Client Component में metadata use कर सकते हैं?
नहीं। metadata export और generateMetadata सिर्फ़ Server Components (page.jsx और layout.jsx) में काम करते हैं। Pages को Server Components रखें और interactivity child components में ले जाएँ।
Title और description कितने लंबे हों?
Title लगभग 60 characters से कम और description 140–160 characters के आसपास रखें ताकि Google search results में पूरा दिखाए।
क्या ranking के लिए JSON-LD ज़रूरी है?
यह सीधा ranking factor नहीं है, पर Google को page समझने में मदद करता है और rich results (FAQ, course, breadcrumb) दिला सकता है, जिससे clicks बढ़ते हैं।
