SEO & Performance Basics (Next.js / Vite)
Quick-reference notes for setting up SEO metadata and squeezing performance out of a Next.js or Vite project. This is a living page — the goal is "if it's not written here, I haven't learned it."
Metadata & Open Graph tags
Next.js (App Router) lets you export a metadata object from a layout or page file instead of hand-writing <head> tags. Anything not natively supported by the typed Metadata object (custom <meta> tags like theme-color, color-scheme, or Twitter/OG tags) goes inside other.
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'JS Mastery',
description: 'JS Mastery Resources',
other: {
'theme-color': '#0d1117',
'color-scheme': 'dark only',
'twitter:image': 'https://i.ibb.co/d6TXXB2/homepage-thumbnail.jpg',
'twitter:card': 'summary_large_image',
'og:url': 'jsmastery.pro',
'og:image': 'https://i.ibb.co/d6TXXB2/homepage-thumbnail.jpg',
'og:type': 'website',
},
};
A few things worth remembering here:
theme-colortells mobile browsers what color to paint the address bar / UI chrome.color-scheme: dark onlyhints to the browser that the page only supports a dark UI, so it won't try to apply light-mode form controls, scrollbars, etc.- The
twitter:*andog:*tags control how the link looks when shared on Twitter/X, Discord, Slack, LinkedIn, etc. Next.js also has a dedicatedopenGraphandtwitterfield on theMetadatatype if you want type safety instead of dumping raw tags intoother— worth switching to once the tags stabilize. - Watch for stray/mismatched quotes when copy-pasting metadata blobs (easy to end up with a
'where a"should be) — it silently breaks the object rather than throwing where you'd expect.
Tools for checking metadata
- opengraph.xyz — paste a URL and preview exactly how the OG/Twitter card will render on different platforms before you ship it. Good for catching wrong image dimensions or missing tags.
- gtmetrix.com — full performance audit (Core Web Vitals, waterfall chart, render-blocking resources). Use this after deploying to see what's actually slow, not just what looks slow locally.
SEO / Performance checklist
Rough order of operations when polishing a site before launch:
- Compress and convert images — ship WebP/AVIF instead of raw JPEG/PNG where possible.
- SEO meta tags — title, description, canonical URL, OG/Twitter tags (see above).
- Favicon — generate source art, then export the full icon set (16px, 32px, 180px Apple touch icon, etc.) via a favicon generator. An AI image tool (e.g. Google's Nano Banana — the nickname for Gemini's native image-generation models, good at quick icon/mark generation from a text prompt) works well for producing a clean square source image fast; then trace/export it as an SVG favicon for crisp rendering at any size, since modern browsers support
<link rel="icon" type="image/svg+xml">. - Minify code — HTML, and whatever your bundler outputs (Vite and Next.js both minify JS/CSS automatically in production builds, but double check
buildoutput isn't accidentally running in dev mode). - Image optimization / lazy-loading — see the framework-specific section below.
Image optimization: Next.js vs. Vite
Next.js — use the built-in <Image /> component (next/image). It handles resizing, format conversion (WebP/AVIF), lazy-loading, and layout-shift prevention out of the box. There's rarely a good reason to use a plain <img> tag for content images in a Next.js app.
import Image from 'next/image';
<Image src="/hero.jpg" alt="Hero banner" width={1200} height={600} priority />;
Vite (no built-in image pipeline) — the most popular choice is vite-plugin-image-optimizer. Add it to vite.config.js and it will automatically compress JPEG, PNG, SVG, and WebP files every time you run a production build.
// vite.config.js
import { defineConfig } from 'vite';
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
export default defineConfig({
plugins: [ViteImageOptimizer()],
});
For lazy-loading in a Vite/vanilla setup where you don't have next/image, the native loading="lazy" attribute on <img> covers most cases without needing a JS library.
Nested CSS
Modern CSS supports native nesting (no Sass/Less required), shipped in all major browsers as of 2023–2024:
.card {
padding: 1rem;
border-radius: 8px;
& .title {
font-size: 1.25rem;
font-weight: 600;
}
&:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
}
Notes:
- The
&explicitly refers to the parent selector, same idea as in Sass. - Nesting a plain element selector (
.card { p { ... } }) works too, but prefixing with&(& p) is the safer/more explicit habit, especially with pseudo-classes and combinators. - Since it's native CSS, no build step or preprocessor is required — but check your target browser support if you need to go further back than ~2023.