#Storing images in astro:db

30 messages · Page 1 of 1 (latest)

split dirge
#

Say I have a table in astro:db that needs an image reference, this image lives in our project not in a CMS or anywhere else, what would the best way of making sure that this image is "synced" with the one that we save in say src/assets?

lime jungleBOT
#

Hi @split dirge. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

I’m sorry, but the provided knowledge sources don’t mention storing images in Astro DB or a built-in way to “sync” image files in src/ with references stored in astro:db.

From the docs we do have:

#

Given that, a safe pattern (based on the docs above) is:

  • Store only a stable key or relative path string in your DB (e.g. "avatar-1.jpg" or "/images/avatar-1.jpg").
  • Resolve that key to an actual import when rendering:
    • If images live under src/, use import.meta.glob to map keys to actual imports, then pass the imported ImageMetadata to <Image /> (per the dynamic imports recipe) (Dynamically import images).
    • If you prefer public/, store the public URL path and render with <img> or <Image /> (supplying width/height) (Files in public, Image properties for public).

This approach avoids duplicating binary data in the DB while keeping the on-disk images as the source of truth and ensures the reference resolves correctly at render time.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The docs don’t specify where to store a “key → image path” map. They only show two workable patterns for resolving a stored key at render time:

  • If images are in src/, keep only a stable key (e.g., "avatar-1.jpg") in your data, and resolve it with import.meta.glob in the component/page to get the actual import (ImageMetadata) before passing to <Image />. This keeps src/ as the source of truth and avoids storing file paths directly in content/data (Dynamically import images, Images in .astro files, Image properties: src).

  • If images are in public/, store the public URL (e.g., "/images/avatar-1.jpg") and render via <img> or <Image /> (supplying width/height when using <Image />) (Files in public, Width/height required for public).

So: put only the key (or public URL) in your DB/content; perform the key→import/URL resolution at render time in your Astro component using the appropriate pattern above. The knowledge sources do not provide a recommended centralized “registry” location beyond this.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
#

@lime jungle I use astro + react, I have an image that lives in src/assets/ how to serve it so it can be used?

lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Use Astro’s image handling based on where the file lives.

If the image is in src/assets:

  • In .astro files: import the file and pass the import to Astro’s Image or Picture component (preferred), or use <img> with the imported .src.
---
// .astro file
import { Image } from 'astro:assets';
import avatar from '../assets/avatar.png';
---
<Image src={avatar} alt="Avatar" />           <!-- optimized -->
<img src={avatar.src} alt="Avatar" />          <!-- unprocessed -->

(Astro components optimize and infer dimensions; <img> is unprocessed) (Images in .astro files, Image, Display unprocessed images).

  • In React components (.jsx/.tsx): import the file, then use <img src={imported.src}>. Astro components aren’t available inside framework components.
import avatar from '../assets/avatar.png';
export default function Avatar() {
  return <img src={avatar.src} alt="Avatar" />;
}

(Images in UI framework components).

Notes:

  • Don’t pass a string file path to <Image />; use the imported image object (or a URL) (Local images must be imported).
  • If you need to pick images dynamically by key, use import.meta.glob to resolve them, then pass the resolved import (ImageMetadata) to <Image /> in a .astro component (Dynamically import images).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
#

@lime jungle in react I get the relative path like /assets/image.webp not the avatar.src

lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

In React components, you must import the image file and use its .src. Passing a string path like "/assets/image.webp" means you didn’t use the ESM import, or you’re relying on old v2 behavior.

Do this in your React file:

import avatar from '../assets/image.webp';

export default function Avatar() {
  return <img src={avatar.src} alt="Avatar" />;
}
  • Framework components can’t use Astro’s <Image />; use the framework’s own <img /> with the imported image’s .src (Images in UI framework components).
  • Since Astro v3, importing an image returns an object with { src, width, height, format }. Update existing <img> tags to use importedImage.src (Update existing <img> tags).
  • If you truly need a plain URL string from the import, append ?url when importing:
import avatarUrl from '../assets/image.webp?url';
<img src={avatarUrl} alt="Avatar" />

(Navigating image imports in v3).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
#

@lime jungle it is a dynamic import, meaning it is a key image in an array of objects, not a direct import

lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Use Vite’s import.meta.glob to map keys to actual image imports, then resolve the chosen key at render time. In a React component, import the image and use its .src.

Example with images in src/assets and a key like "avatar-1.jpg":

---
// Wrapper .astro component to resolve the image dynamically, then pass to React
import type { ImageMetadata } from 'astro';
import ReactCard from '../components/ReactCard.jsx';

const images = import.meta.glob<{ default: ImageMetadata }>('/src/assets/*.{jpeg,jpg,png,gif,webp}');
const { key, ...rest } = Astro.props;

if (!images[`/src/assets/${key}`]) {
  throw new Error(`"${key}" not found in /src/assets/*.{jpeg,jpg,png,gif,webp}`);
}

const mod = await images[`/src/assets/${key}`](); // dynamic import -> { default: ImageMetadata }
const img = mod.default;
---
<ReactCard src={img.src} width={img.width} height={img.height} {...rest} />
// ReactCard.jsx
export default function ReactCard({ src, width, height, alt }) {
  return <img src={src} width={width} height={height} alt={alt} />;
}
#

Notes:

  • import.meta.glob returns functions you invoke to load the module; with ImageMetadata you get { src, width, height, format } that you can pass to React’s <img> (Dynamically import images, Display unprocessed images).
  • You cannot pass a string like "../file.png" to Astro’s <Image />; local images must be imported or resolved via glob/import before use (Local images must be imported, Images in .astro files).
  • Alternatively, do the same resolution directly inside a .astro component and render <Image src={resolvedImport} /> if you prefer optimization in Astro, then pass the resulting markup as children to a React component if needed (Images in UI framework components).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
#

@lime jungle any better way of doing this?

// Import all assets from src/assets directory
const assets = import.meta.glob<{ default: { src: string } }>(
  "../assets/**/*.(webp|png|jpg|jpeg|gif|svg)",
  {
    eager: true,
  }
);

export function getAssetPath(path: string): string {
  // Remove leading slash if present
  const cleanPath = path.startsWith("/") ? path.slice(1) : path;

  // Look for the asset in the imported assets
  for (const [assetPath, asset] of Object.entries(assets)) {
    // Extract the relative path from the asset path
    // assetPath format: "../assets/plaques/google.webp"
    const relativePath = assetPath.replace("../assets/", "");

    if (relativePath === cleanPath) {
      return asset.default.src;
    }
  }

  // Fallback to public assets if not found in src/assets
  return `/assets/${cleanPath}`;
}

lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Yes. Use import.meta.glob with a strict, root-anchored pattern and avoid manual iteration by keying the map with your expected paths. Also, you don’t need eager unless you truly want all images loaded up front.

Example pattern:

// 1) Build a map keyed by absolute-like keys you store (e.g. "/src/assets/plaques/google.webp")
const images = import.meta.glob('/src/assets/**/*.{webp,png,jpg,jpeg,gif,svg}'); // functions
// or, if you need metadata immediately: { eager: true } and type to ImageMetadata

export async function getAssetPath(key: string): Promise<string> {
  // Normalize key to a full path starting at /src
  const full = key.startsWith('/src/') ? key : `/src/assets/${key.replace(/^\/?/, '')}`;
  const loader = images[full];
  if (!loader) {
    // fallback to public/ assets by URL if you store some there
    return `/assets/${key.replace(/^\/?/, '')}`;
  }
  const mod = await loader(); // { default: ImageMetadata }
  return mod.default.src;
}

Why:

  • Glob patterns must be static string literals and begin with ./, ../, or /; using a root-anchored string avoids relative path fiddling and string replaces (Glob patterns in Astro).
  • import.meta.glob returns a map of loaders you can index directly by the full path, so you don’t need to loop over entries. When typed to ImageMetadata, you can read .src (and width/height) to pass to <img> or your React component (import.meta.glob, Dynamically import images recipe).

If you prefer eager loading (sync API), use:

const images = import.meta.glob<{ default: ImageMetadata }>(
  '/src/assets/**/*.{webp,png,jpg,jpeg,gif,svg}',
  { eager: true }
);
#

export function getAssetPath(key: string): string {
const full = key.startsWith('/src/') ? key : /src/assets/${key.replace(/^\/?/, '')};
const mod = images[full];
if (!mod) return /assets/${key.replace(/^\/?/, '')};
return mod.default.src;
}

This aligns with the documented dynamic import approach and avoids brittle path rewriting and iteration ([Dynamically import images](<https://docs.astro.build/en/recipes/dynamically-importing-images/#recipe>)).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
#

@split dirge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

split dirge
#

@lime jungle Why using in <img /> just /src/assets/relative-path worked then?

lime jungleBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Short answer: it shouldn’t. Using a “/src/…” path in an <img> isn’t a supported pattern in the docs.

If “/src/assets/relative-path” appeared to work locally, that’s not a documented guarantee and may break in production builds where assets are fingerprinted and moved (e.g., to /_astro/...). The recommended, supported approaches are:


Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: