Framework guides

How each of the six example stacks reads kura, grounded in real repo code

kura is just a REST API, so it works with any frontend. The six example repos each read from a real kura project in a different stack - clone any one to scaffold a real site. This page shows how each reads kura, grounded in the actual code in each repo.

The shape every framework shares

Every example makes the same call: GET {base}/api/v1/{project}/{type} with an Authorization: Bearer {token} header, and reads body.data (the entries) from the envelope. They keep three values in config:

KURA_BASE_URL=https://kuracms.com
KURA_PROJECT=your-project-slug
KURA_TOKEN=kr_live_your_token

Always read kura server-side or at build time so the token never ships in the browser bundle - every example below does this.

Two execution patterns:

  • Request-time (SSR): Astro, Next.js, Nuxt, SvelteKit fetch on each request, so published edits appear on the next page load.
  • Build-time (static): Eleventy and Hugo fetch during the build into JSON data files, so published edits appear only after a rebuild (see the note at the end).

Astro (kura-property-example)

Config in .env. Fetches at request time in a client() + typed fetch helper (src/lib/kura.ts):

const url = `${base}/api/v1/${project}/listing${qs.size ? `?${qs}` : ""}`;
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
const body = await res.json();
return body.data.map((l) => resolveMedia(l, base));

This one shows the media prefix done properly - resolveMedia prepends the base URL to any /media/... value:

if (v.startsWith("/media/")) return base + v;

Called from .astro pages during server render.

Next.js (kura-restaurant-example)

Config in wrangler.jsonc vars (falls back to process.env for next dev). Server components fetch at request time with cache: "no-store" so editor changes show immediately (src/lib/kura.ts):

const url = `${base}/api/v1/${project}${qpath}`;
const res = await fetch(url, { headers, cache: "no-store" });

It rewrites /media/ paths inside markdown/HTML body text before rendering:

text.replace(/(\]\()(\/media\/)/g, `$1${base}$2`)
    .replace(/(["'\s])(\/media\/)/g, `$1${base}$2`);

Deployed to Cloudflare Workers via OpenNext; revalidate = 0 keeps it request-time.

Nuxt (kura-salon-example)

Config via runtimeConfig.public (set from NUXT_PUBLIC_KURA_* vars in wrangler.jsonc). Fetches in a composable with useAsyncData (composables/useKura.ts):

const url = `${cfg.kuraBaseUrl}/api/v1/${cfg.kuraProject}${path}`;
const res = await $fetch(url, { headers: { Authorization: `Bearer ${cfg.kuraToken}` } });
export function useServices() {
  return useAsyncData("services", async () => {
    const r = await kuraFetch(`/service?limit=50`);
    return r.data.filter((s) => s.published);
  });
}

SvelteKit (kura-clothing-example)

Config from the Cloudflare platform env (falls back to process.env in dev). Fetches in a +page.server.ts load function (src/lib/kura.ts):

const url = `${cfg.baseUrl}/api/v1/${cfg.project}${path}`;
const res = await fetchFn(url, { headers: { Authorization: `Bearer ${cfg.token}` } });
export async function fetchProducts(fetchFn, platform) {
  const r = await kuraFetch(fetchFn, platform, `/product?limit=100`);
  return r.data.filter((p) => p.published !== false);
}

Eleventy - static (kura-architecture-example)

A static site, so it fetches at build time with a shell script (fetch-content.sh) that curls kura and writes JSON into _data/, which Eleventy reads as global data:

curl -fsSL -H "Authorization: Bearer ${KURA_TOKEN}" \
  "${KURA_BASE}/api/v1/${KURA_PROJECT}/${type}?limit=50" > _data/${type}-raw.json
# then a small python filter to published-only + sort, written to _data/{type}.json

KURA_TOKEN etc are environment variables set at deploy time (see the repo README). Templates read _data/*.json during eleventy build.

Hugo - static (kura-escape-example)

Same build-time pattern: fetch-content.sh curls kura into data/*.json, then hugo --minify reads .Site.Data.rooms etc:

curl -fsSL -H "Authorization: Bearer ${KURA_TOKEN}" \
  "${KURA_BASE}/api/v1/${KURA_PROJECT}/room?limit=50" > data/rooms-raw.json

Two notes that bite

Media paths. kura returns uploaded images as relative /media/{key} strings. The Astro and Next.js examples prefix them with the base URL (shown above); the others happen to use absolute image URLs in their seed data, so they render as-is - but if your content uses kura image uploads, prefix /media/ paths with KURA_BASE_URL. See the REST API reference.

Static sites need a rebuild to show edits. Eleventy and Hugo fetch at build time, so an editor publishing a change won't see it until the site rebuilds. Wire your host's deploy hook (e.g. a Cloudflare Pages / Workers build hook) to fire on publish. The SSR stacks (Astro, Next.js, Nuxt, SvelteKit) don't have this - they read kura on each request.


Building from scratch rather than cloning? See the tutorial and the REST API reference.