BorisovAI
All posts
New Featureborisovai-siteClaude Code

Adding SEO Metadata to Project Pages in Next.js

Adding SEO Metadata to Project Pages in Next.js

I was deep in the Borisov AI project, working on the Strapi+PostgreSQL integration branch, when I realized something was broken: our project showcase pages had zero SEO. No titles, no descriptions, no Open Graph tags. Search engines saw nothing.

The problem was obvious once I looked at the code. The [slug]/page.tsx component fetched project data from Strapi but never exported generateMetadata. Every project page rendered with the same generic title from the root layout. That’s a silent killer for discoverability—we could have fifty projects indexed as “BorisovAI” with identical descriptions.

I started by mapping what we actually had. The Strapi API was already feeding us rich data: project title, description, thumbnail image. The Next.js pages component pattern was solid. We just needed to wire it up to the metadata system.

The fix came in three parts. First, I extracted the project-fetching logic so it could run in both the component and the metadata generator without duplication—Next.js dedupes identical fetch calls automatically, so no extra API hit. Second, I built the metadata object: title becomes “Project Name — BorisovAI”, description pulls directly from Strapi, and openGraph properties feed the thumbnail as og:image. Third, I added language alternates for the hreflang tag and set canonical to prevent duplicate content issues between /en/projects/slug and /ru/projects/slug.

One unexpected wrinkle: the thumbnail URL from Strapi needed the full domain prefix. We store just the path in Strapi, so I had to route it through getStrapiMediaUrl, which was already in the codebase. Small thing, but it mattered when Open Graph crawlers couldn’t find the image.

The metadata now covers the essentials. The <title> tag is specific per project. Meta descriptions appear in search snippets. Open Graph works for Twitter, Slack, and LinkedIn shares. The layout already had a metadataBase set, so canonical URLs resolve correctly.

It’s not fancy—no schema markup, no breadcrumbs yet—but it’s functional. The next developer who audits our SEO will find actual project titles instead of generic stubs. And that’s worth the thirty minutes it took to wire it up.

Metadata

Session ID:
grouped_borisovai-site_20260522_1418
Branch:
feat/postgres-strapi-pgvector
Dev Joke
Что общего у Cypress и подростка? Оба непредсказуемы и требуют постоянного внимания

Rate this content

0/1000