Strapi Media Library Fallback for Empty Image Fields
Fix null Strapi media fields on REST and GraphQL responses by generating dimension-matched placeholder URLs before they reach your frontend components.
Strapi media fields are optional by default. When an entry is created without a file attached, the field value is null in both the REST API response and the GraphQL response. Frontends that omit a null check render a broken image or throw a runtime error trying to access properties on null.
Adding a fallback URL at the data layer — before the value reaches a component — keeps layouts stable and eliminates the broken-image icon. fallback.pics generates dimension-correct SVG placeholders from the URL, so you do not need to store or serve any extra assets in your Strapi media library.
Strapi API responses
How Strapi returns null media fields
Strapi v4 wraps collection entries in a `data` envelope. A media field returns `null` as its full value when nothing has been uploaded: `{ data: { id: 1, attributes: { image: { data: null } } } }`. Code that navigates straight to `attributes.image.data.attributes.url` throws a TypeError on null.
GraphQL responses follow the same pattern. The generated schema makes media fields nullable, so queries succeed but the image object is null. Apollo Client and similar tools do not throw on null fields — the component receives null and must handle it.
Bulk imports are a frequent cause of null media. When content is migrated from another CMS or seeded from a spreadsheet, text fields populate first while images are uploaded separately. There is always a window when entries are public but image fields are not yet set.
REST helper
Extract the media URL safely from a Strapi response
Write a utility that accepts the full Strapi media object and returns either the real URL or a fallback. Make the fallback dimensions a required argument so each call site is explicit about the slot size.
Strapi serves files from its own domain when using the local upload provider. If you use a cloud provider like Cloudinary or AWS S3 through a Strapi plugin, the URL comes from the external CDN instead. The helper needs to handle both — or simply forward whatever URL Strapi provides.
// lib/strapi-image.ts
interface StrapiMedia {
data: {
attributes: {
url: string;
width?: number;
height?: number;
formats?: Record<string, { url: string }>;
};
} | null;
}
export function strapiImageUrl(
media: StrapiMedia | null | undefined,
width: number,
height: number,
label = '',
): string {
const url = media?.data?.attributes?.url;
if (url) {
return url.startsWith('/') ? `${process.env.NEXT_PUBLIC_STRAPI_URL}${url}` : url;
}
const text = label ? encodeURIComponent(label) : `${width}x${height}`;
return `https://fallback.pics/api/v1/${width}x${height}?text=${text}`;
} Responsive formats
Use Strapi format variants or fall back gracefully
Strapi generates multiple format variants (thumbnail, small, medium, large) for images above certain thresholds. These are stored under `attributes.formats`. If you target a specific format for a card thumbnail and the uploaded image was too small for Strapi to create that variant, `formats.medium` will be undefined even though the original image exists.
Your helper should check the target format first, fall back to the original URL if the format is missing, and then fall back to the generated placeholder URL if the original is also absent. Three-level fallback chains are common in production Strapi deployments.
export function strapiThumbnailUrl(
media: StrapiMedia | null | undefined,
width: number,
height: number,
): string {
const attrs = media?.data?.attributes;
const src =
attrs?.formats?.medium?.url ??
attrs?.formats?.small?.url ??
attrs?.url;
if (src) {
return src.startsWith('/')
? `${process.env.NEXT_PUBLIC_STRAPI_URL}${src}`
: src;
}
return `https://fallback.pics/api/v1/${width}x${height}?text=No+Image`;
} GraphQL
GraphQL query patterns with nullable image fields
When querying Strapi with GraphQL, request the url, width, and height from the media attributes. Having width and height in the response lets you pass matching dimensions to the fallback URL rather than hardcoding them for each query.
Use fragments to avoid repeating image field selection across multiple queries. One `MediaFields` fragment covers every content type that includes a media relation.
fragment MediaFields on UploadFileEntityResponse {
data {
attributes {
url
width
height
alternativeText
}
}
}
query GetArticle($slug: String!) {
articles(filters: { slug: { eq: $slug } }) {
data {
attributes {
title
cover { ...MediaFields }
author {
data {
attributes {
avatar { ...MediaFields }
}
}
}
}
}
}
} Bulk imports
Protect pages during content migration
When importing content from a spreadsheet or legacy CMS, images typically arrive after the initial text import. If you publish entries before the media upload script completes, live pages will have null image fields for a period of time.
The fallback URL provides a graceful degradation during this window. Users see a labeled placeholder rather than a broken icon, and search crawlers do not encounter broken image references that might affect indexing.
Resources
Further reading
See the full API parameter list on the fallback.pics docs. The general CMS placeholder guide covers patterns shared across Strapi, Contentful, and Sanity.
https://fallback.pics/docs/
https://fallback.pics/placeholder-image-api/
https://fallback.pics/blog/contentful-image-field-fallback/
https://fallback.pics/blog/sanity-cms-image-fallback/ Key takeaways
What to standardize before shipping
- Strapi media fields return null when no file is attached — the v4 data envelope requires navigating data.attributes.url safely.
- Write a strapiImageUrl helper that checks the format variant, original URL, then falls back to a generated placeholder URL.
- Pass matching width and height to fallback.pics to prevent layout shift.
- Request width and height in GraphQL queries so dimension-matched fallbacks require no hardcoding.
- Fallback URLs protect live pages during bulk content imports when images arrive after text entries.
Production fallback layer
Use fallback.pics anywhere an image URL is accepted.
Start with one deterministic URL and standardize fallback behavior across your design system.