Use Astro's Image component with the Keystatic image field

Astro provides a built-in <Image /> component that helps display optimized versions of local images.

This guides walks you through the configuration needed to use the <Image /> component with the image field in Keystatic.

Storing images in Astro's src/ directory

To make use of Astro's <Image /> component, you need to store your images somewhere within the src/ directory of your project. A common convention is src/assets, but any subdirectory under src/ will work.

You can control where Keystatic stores images using the directory option in the Keystatic config.

☝️

We recommend creating a path alias for your images directory in your .tsconfig.json file — it simplifies referencing the path to that directory. Here's an example using the common src/assets convention:

// .tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@assets/*": ["./src/assets/*"],
    },
  }
}

Standalone image field

Images stored in a standalone image field (not inside a MDX or Markdoc document) will be stored in your frontmatter data in Astro's content collections.

⚠️

You need to configure the Zod content collection schema in Astro, and use the image helper for the image metadata transformation to work.

Refer to this section of the Astro documentation for more information.

Using the path alias suggested above, you can setup your image field options like this:

image: fields.image({
  label: 'Image',
  directory: 'src/assets/images/posts',

  // Use the @assets path alias
  publicPath: '@assets/images/posts/'

})

As long as the image path stored is within the src/ directory, Astro will be able to process it into image metadata that the <Image /> component can use.


Images inside MDX or Markdoc fields

Images uploaded via the MDX or Markdoc fields can be configured the same way as standalone image fields via the options object:

content: fields.mdx({
  label: 'Content',
  options: {
    image: {
      directory: 'src/assets/images/posts',

      // Use the @assets path alias
      publicPath: '@assets/images/posts/'
    
    }
  }
})

Just like standalone image fields, you will need to configure the Zod schema with the image helper for the image metadata transformation to work.


Content component images

Using Astro assets within content components is a little more complicated.

Since the image is not stored in the frontmatter data but directly within the content body, you'll need to dynamically import the image inside the component you're using to render that content component.

⚠️

The publicPath for those images must start with /src/ for the dynamic import to work in Astro.

Here's how you should configure the image field inside content components:

// Inside a MDX or Markdoc field...
captionImage: block({
  label: 'Caption Image',
  schema: {
    image: fields.image({
      label: 'Image',
      directory: 'src/assets/images/posts',

      // start with /src/
      publicPath: '/src/assets/images/posts/'

    }),
    // other fields...
  }
})

Read the Astro guide on dynamic image imports for details on the implementation.