Image maintenance
Though valuable for user understanding, images are difficult to maintain. We have a few strategies that we use to help make this easier.
We support a few different types of images in our docs, including:
Of these, we prefer Mermaid diagrams because they are searchable and easily changeable. The "cost" of updating a Mermaid diagram is much lower than re-taking a screenshot or working with a designer to update a diagram.
The best way to improve image maintenance is to avoid using them.
The other way to streamline maintenance is to remove images that are no longer referenced in your documentation. This pattern becomes particularly helpful if you need to audit images for UI changes or leaked information, because then you are not wasting time looking at unused images too.
We do that through a combination of GitHub actions.
We have a specific GitHub action to flag unused images ↗.
What the GitHub action does is:
- Finds all
.png
or.svg
files in our content. - Checks to see if those files are referenced in any of our MDX files.
- Ceates a GitHub issue ↗ if there are unreferenced files.
In combination with flagging unused images, we also have logic in our build process ↗ to validate image paths.
export default defineConfig({ site: "https://developers.cloudflare.com", markdown: { smartypants: false, remarkPlugins: [remarkValidateImages], rehypePlugins: [ rehypeMermaid, rehypeExternalLinks, rehypeHeadingSlugs, rehypeAutolinkHeadings, // @ts-expect-error plugins types are outdated but functional rehypeTitleFigure, rehypeShiftHeadings, ], },
This line ensures that our custom Remark plugin ↗ validates all images paths. If the path does not exist, we throw an error and prevent the site from building.
import { existsSync } from "node:fs";import { join } from "node:path";import { visit } from "unist-util-visit";
import type { Node } from "unist";import type { VFile } from "vfile";
interface ImageNode extends Node { type: "image"; url: string; position?: { start: { line: number; column: number }; end: { line: number; column: number }; };}
export default function validateImages() { const rootDir = process.cwd();
const assetsDir = join(rootDir, "src", "assets"); const publicDir = join(rootDir, "public");
return (tree: Node, file: VFile) => { visit(tree, "image", (node: ImageNode) => { const { url } = node; let fullPath: string;
if (url.startsWith("~/assets/")) { fullPath = join(assetsDir, url.slice(9)); } else if (url.startsWith("/")) { fullPath = join(publicDir, url); } else { // Remote image or unrecognised URL return; }
if (!existsSync(fullPath)) { const position = node.position ? ` at line ${node.position.start.line}, column ${node.position.start.column}` : "";
const error = new Error( `Image not found: "${url}"${position} in ${file.path}\n` + `Expected to find at: ${fullPath}`, ) as Error & { file?: string };
error.file = file.path; throw error; } }); };}
When paired with flagging unused images, this path validation ensures that a tech writer can safely delete unused files in a pull request. So long as the site builds correctly, you have only deleted image files that are not referenced anywhere.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-