---
title: Nuxt
description: Read and render what you publish from a Nuxt site with @hollware/nuxt, over a service binding or a read token, with previews and images ready.
section: frameworks
order: 1
---

# Nuxt

`@hollware/nuxt` is a Nuxt module: composables that read published content, components that render it, previews of drafts, and a cache that Hollware purges when you publish.

```sh
npm install @hollware/nuxt
```

## Configure it

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@hollware/nuxt'],
  hollware: { site: 'my-site' },
  nitro: { preset: 'cloudflare_module', cloudflare: { deployConfig: true, nodeCompat: false } },
})
```

On Cloudflare, bind your Hollware Worker in the site's `wrangler.jsonc`, and the module reads over it, with no network and no token:

```jsonc
"services": [{ "binding": "HOLLWARE", "service": "my-cms", "entrypoint": "Hollware" }]
```

Anywhere else, set `hollware.url` to the address of your Hollware and a read token (`npx hollware token create --read`) in `NUXT_HOLLWARE_TOKEN`. The token stays on the server: pages read through the site's own `/_hollware/` routes.

## Show an entry

```vue
<script setup lang="ts">
const route = useRoute()
const { data } = await useHollwareEntry('blog', 'en', route.params.slug as string)
</script>

<template>
  <article v-if="data">
    <h1>{{ data.entry.frontmatter.title }}</h1>
    <HollwareImage :entry="data.entry" field="img" />
    <HollwareContent :entry="data.entry" :components="{ callout: Callout }" />
  </article>
</template>
```

- **`<HollwareContent>`** renders the entry from the document Hollware stored when it was written: no Markdown parser reaches the page. `components` maps the components of your entries (`::callout`) to your own Vue components; anything else renders as its plain tag. Its images come with their `srcset`, `sizes`, `width` and `height`.
- **`<HollwareImage>`** renders the image a frontmatter field holds, such as a cover, with its alt, its size and the copies Hollware made of it. Any attribute you give wins: `<HollwareImage :entry field="img" loading="lazy" sizes="50vw" />`.

An entry that is not published answers a 404.

## Lists, translations and the site

```vue
<script setup lang="ts">
const { data } = await useHollwareEntries('blog', { locale: 'en', limit: 10 })
</script>

<template>
  <ul>
    <li v-for="post in data?.entries" :key="post.id">
      <HollwareImage :entry="post" field="img" loading="lazy" />
      <NuxtLink :to="`/blog/${post.slug}/`">{{ post.frontmatter.title }}</NuxtLink>
    </li>
  </ul>
</template>
```

| Composable | Gives |
| --- | --- |
| `useHollwareEntry(collection, locale, slug)` | a published entry, with its document |
| `useHollwareEntries(collection, { locale, tag, limit, cursor })` | a page of published entries, newest first |
| `useHollwareTranslations(collection, group)` | the entries of a translation group |
| `useHollwareSite()` | the site: its locales and collections |
| `useHollware(event)` (server) | the reader itself, for routes of your own |

The fields your collection has Hollware fill, such as a date or the reading time, come filled in the frontmatter ([Configure your content](/docs/configure-your-content/)).

## Previews

**Preview on the site**, in the admin, opens the entry's page with a signed link for that one entry, valid for an hour. The module exchanges the link for an `HttpOnly` cookie, reads the latest revision of the entry, a draft included, and keeps nothing it answers. It needs the site's `url` in the admin, under **Site**.

## Cache

`hollware.cache: 'purge'` keeps the pages of your site in Workers Cache and lets Hollware purge them, by tag, the moment you publish. See [Caching](/docs/caching/).

Every page carries `<meta name="generator" content="Hollware">`; `hollware.generator: false` leaves it out.

## A whole site

`examples/nuxt-blog` in the repository is a Nuxt blog on a Worker that reads the playground over a service binding, previews included.
