React SME Cookbook
All FAQs

Search Documentation

Search across all documentation pages

best-practicessummaryimages-icons

Images & Icons Best Practices

A condensed summary of the 25 most important best practices drawn from every page in this section.

  1. Prefer next/image Over img: Use next/image so Next.js automatically serves WebP/AVIF, lazy-loads offscreen images, and generates responsive sizes. The raw <img> tag ships no optimization and hurts LCP.
  2. Always Pair fill With sizes: Using fill without a sizes prop makes the browser download the largest variant for every device. Provide a breakpoint-aware sizes string that matches your actual layout columns.
  3. Set position: relative on fill Parents: A fill image's parent must have position: relative (or absolute/fixed) plus defined dimensions, or the image collapses to zero height. Use an aspect-ratio wrapper to lock the layout.
  4. Reserve priority for LCP Images: Only add priority to above-the-fold hero images (typically one or two per page). Overusing it cancels the lazy-loading benefit of next/image.
  5. Configure remotePatterns Explicitly: Add every external image host (e.g., images.unsplash.com, images.pexels.com, cdn.pixabay.com) to images.remotePatterns in next.config.ts and restart the dev server. Missing entries cause 400 errors at runtime, not at build time.
  6. Prefer Static Imports for Local Images: Static imports return StaticImageData with width, height, and an auto-generated blurDataURL, eliminating manual boilerplate. They also enable placeholder="blur" without extra work.
  7. Use width/height Only for Aspect Ratio: The width and height props define the requested size and aspect ratio — they do not resize or crop the rendered element. Control visual sizing with CSS classes.
  8. Never Expose API Keys in the Browser: Unsplash, Pexels, and Pixabay keys must stay server-side; fetch from Server Components or Route Handlers and store secrets in .env.local. Pixabay is especially risky because the key is a query parameter.
  9. Cache API Responses With revalidate: Wrap stock-photo fetches with next: { revalidate: 3600 } so you stay inside hourly rate limits (Unsplash 50/5000, Pexels 200, Pixabay 100/min) and keep pages fast. This also avoids hammering third-party APIs on every request.
  10. Use the Right Auth Header Format: Unsplash requires Authorization: Client-ID <key>, Pexels requires the raw key with no Bearer prefix, and Pixabay uses a key query parameter. Mixing these up returns a 401 and wastes debugging time.
  11. Pick the Right URL Size: Use regular/webformatURL/large for display and reserve raw/original/fullHDURL for downloads, since originals can exceed 10MB. Serving oversized images undoes the point of an optimization pipeline.
  12. Honor Attribution and Download Tracking: Unsplash requires photographer credit with UTM params and a call to download_location whenever a photo is used. Pexels and Pixabay strongly encourage attribution even when not strictly required.
  13. Treat API alt Text as Untrusted: Fields like Pexels alt or Unsplash alt_description can be empty, generic, or null. Provide a meaningful fallback to keep images accessible.
  14. Never Hotlink Pixabay in Production: Pixabay's license permits only temporary CDN hotlinking; for production, download and re-host images on your own infrastructure. Plan a build step or ingestion pipeline accordingly.
  15. Import Icons From Family Sub-Paths: Always import react-icons from a family path like react-icons/fa — importing from the package root can defeat tree-shaking and bundle thousands of unused icons. The same discipline applies to any barrel-style icon import.
  16. Style Heroicons With className Only: Heroicons ignore size and color props; set dimensions and color via Tailwind utilities such as h-6 w-6 text-blue-500. Alias imports when using both outline and solid variants of the same icon in one file.
  17. Type Icons as Components, Not Elements: Use LucideIcon, IconType, or React.ComponentType<SVGProps<SVGSVGElement>> to type icon props so you can render them with <Icon size={…} />. Passing a rendered element instead of a component type breaks reusable button wrappers.
  18. Mark IconContext Providers as Client: IconContext.Provider from react-icons uses React Context and must live in a Client Component in the App Router. Place it high enough in the tree to cover the subtree you want to style.
  19. Use currentColor for Custom SVGs: Set stroke="currentColor" (or fill="currentColor") on inline SVG icons so they inherit color via parent text-* classes. This makes a hand-rolled icon set behave like Lucide or Heroicons.
  20. Make SVG Accessibility Explicit: Decorative icons should have aria-hidden="true" and no role; informative icons need role="img" plus an aria-label. Also write SVG attributes in camelCase (viewBox, strokeWidth) and keep viewBox even after SVGO optimization.
  21. Set fill and stroke Defaults Intentionally: SVG defaults fill and stroke to black, so stroke-based icons need fill="none" and filled icons need stroke="none" to avoid surprise rendering. Lucide's stroke-only behavior is a concrete example — fill has no effect there.
  22. Generate blurDataURLs at Build Time: Produce BlurHash or tiny JPEG blurDataURLs (around 8x8 pixels) ahead of time and cache them with your image metadata. Generating them per request with sharp adds latency and can't run on the Edge Runtime.
  23. Match Skeleton Dimensions to Final Content: Shimmer or aspect-ratio skeletons must use the same aspect ratio as the loaded image so the layout does not shift (CLS). Apply CSS blur() only to tiny placeholders, never to full-resolution images.
  24. Follow Next.js Metadata File Conventions: Place favicon.ico in app/ root, and drop icon.*, apple-icon.*, opengraph-image.*, and twitter-image.* into the route segments where they should apply. Next.js wires them into <head> automatically and scopes OG images per route.
  25. Design OG Images Around Satori Limits: ImageResponse from next/og uses Satori, which supports only flexbox (no grid), no background-image: url(), and requires fonts loaded as ArrayBuffer. Target 1200x630, export an alt, and prefer runtime = "edge" for fast, cacheable per-page images.