ADDING IMAGES TO MARKDOWN WITH NUXT CONTENT MODULE

Adding Images To Markdown With Nuxt Content Module

When I first started building this blog with Nuxt Content, I hit a wall trying to add images to my markdown posts. Standard markdown image syntax didn't work the way I expected. I needed a way to optimize images, add lazy loading, and make them work seamlessly in markdown.

The modern solution? Use @nuxt/image with images in the static/ folder. It handles optimization, lazy loading, and responsive images automatically.

The Modern Approach: Static Folder + @nuxt/image

After trying various approaches, here's what actually works in production:

Where to Store Images

Put your images in the static/blog/ folder (not assets/):

static/
  blog/
    hero-image.webp
    screenshot.png
    diagram.svg

The static folder serves files directly without webpack processing.

Using Images in Markdown Content

In your Nuxt Content markdown files, use regular <img> tags:

<img src="/blog/screenshot.png" alt="Project screenshot" loading="lazy" />

Why not <nuxt-img>? The <nuxt-img> component doesn't work inside Nuxt Content markdown files. It only works in Vue templates and components.

Using @nuxt/image in Vue Templates

For hero images and thumbnails in your Vue components, you can use <nuxt-img> with responsive optimization:

<template>
  <nuxt-img :src="`/blog${article.thumbnail}`" :alt="article.title" loading="lazy" sizes="sm:100vw md:100vw lg:900px" />
</template>

Install the module:

npm install @nuxt/image

Add it to nuxt.config.js:

export default {
  modules: ["@nuxt/image"],
  image: {
    screens: {
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1920
    }
  }
};

This gives you automatic image optimization and responsive sizes for hero images and preview thumbnails in your Vue templates.

Why This Works Better

Before (old v-img approach):

  • Images in assets/ folder
  • Webpack bundling required custom component
  • Manual optimization needed
  • Complex setup

After (static folder + @nuxt/image):

  • Images in static/ folder - simple and direct
  • Regular <img> tags in markdown - no custom component needed
  • @nuxt/image optimization for hero images in Vue templates
  • Responsive sizes where it matters (thumbnails, hero images)

Pre-Optimize Your Images

Since you're using regular <img> tags in markdown, pre-optimize your images before adding them to static/blog/:

# Resize to 1920px max width
sips -Z 1920 input.png --out temp.png

# Convert to WebP with 85% quality
cwebp -q 85 temp.png -o static/blog/output.webp

# Clean up
rm temp.png

This gives you the best of both worlds:

  • Manually optimized images (100-200KB instead of 5-6MB)
  • @nuxt/image responsive optimization for hero/thumbnail images in Vue templates
  • Simple <img> tags in markdown that just work

The Old Way (Legacy)

Before this approach, you needed a custom VImg component with webpack's require() to bundle images from the assets/ folder. That approach still works but is overcomplicated.

The static folder approach is simpler, more reliable, and works consistently across development and production builds.

Performance Results

After switching to this approach:

  • Hero images serve responsive sizes automatically (640px on mobile, 1920px on desktop)
  • Manually optimized WebP images in content (63-185KB each, 98% smaller than original PNGs)
  • Native lazy loading on all images
  • Better Core Web Vitals scores

Keep it simple: optimize images manually, store them in static/blog/, use regular <img> tags in markdown.