← knowledge.oriz.in

Image host — chained 4-tier origin (repo + ImgBB + Imgur + GitHub user-content)

decision imageshostoriginfallbackoriz-kitnever-hit-quotas

Image host — chained 4-tier origin (repo + ImgBB + Imgur + GitHub user-content)

Decision

Image origin storage uses a 4-tier fallback chain, distinct from (and composed with) the 3-tier image-CDN chain that handles delivery / transformation:

  1. repo-hosted on Cloudflare Pages — default for everything that fits in the repo. Image lives next to the .mdx that embeds it.
  2. ImgBB — uploaded by CI for blog-post images that don't belong in the repo (large screenshots, automated batch uploads).
  3. Imgur — mirror of Tier 2; same payload pushed in parallel from CI for hot-link backup.
  4. GitHub user-content — rare; assets > 25 MB, large animated GIFs we don't want in the site repo, PNG-must-stay-PNG cases. Uses an orphan assets branch of any family repo, hot-linked via raw.githubusercontent.com.

User direction 2026-06-20: "use all of them and add all imgbb and imgur and github user content and repo hosted" — locked.

Why

Origin vs CDN — composition with the existing chain

[ Tier 1 origin: /posts/2026/hero.png on CF Pages         ]
                              ¦
                              ?
[ CDN Tier 1: Cloudflare Images /cdn-cgi/image/<opts>/... ]
   ? on 5xx
[ CDN Tier 2: wsrv.nl?url=<encoded origin url>            ]
   ? on 5xx
[ CDN Tier 3: ImageKit                                    ]

If the ORIGIN itself goes 404 (Tier 1 missing, e.g. a typo'd path that escaped review), the kit falls to the next ORIGIN tier:

Tier 1 origin 404
   ?
Tier 2 origin (ImgBB URL from frontmatter)
   ?
Tier 3 origin (Imgur URL from frontmatter)
   ?
Tier 4 origin (GitHub raw URL from frontmatter)

Implementation hint

The <Image> component in ships a src chain. Frontmatter on a post (or asset metadata) lists all available tiers; the wrapper tries Tier 1 ? on error falls through to Tier 2 ? etc. Each origin URL is then wrapped by the CDN chain on the way out.

// inside @chirag127/oriz-kit
const ORIGIN_KEYS = ['src', 'imageTier2', 'imageTier3', 'imageTier4'] as const;

export function Image({ origins, ...opts }) {
  const [tier, setTier] = useState(0);
  const origin = origins[ORIGIN_KEYS[tier]];
  const wrapped = wrapWithCdnChain(origin, opts);   // existing 3-tier CDN chain
  return (
    <img
      src={wrapped}
      onError={() => setTier(t => Math.min(t + 1, ORIGIN_KEYS.length - 1))}
      {...opts}
    />
  );
}

The frontmatter shape for a post embedding an image:

---
title: "..."
images:
  hero:
    src: ./hero.png                          # Tier 1 — repo-hosted
    imageTier2: https://i.ibb.co/.../...     # Tier 2 — ImgBB
    imageTier3: https://i.imgur.com/....png  # Tier 3 — Imgur mirror
    imageTier4: https://raw.githubusercontent.com/chirag127/blog-site/assets/2026/06/hero.png  # Tier 4
---

CI mirrors Tier 1 ? Tiers 2 + 3 + 4 on every post merge so the chain is populated for new content automatically.

Implications

Cross-refs