Back to templates

Template details

NuxtBooks

Browse a curated catalog of 100,000 Goodreads books built with Nuxt 4, Nitro caching, and Drizzle on a free Neon database tier.

About this template

NuxtBooks is a Nuxt 4 book catalog template that serves a curated 100,000-book Goodreads subset small enough to fit within the free Neon database tier. It rebuilds Vercel Labs' NextBooks in Nuxt and ships as an open-source GitHub project.

What is NuxtBooks?

NuxtBooks is a full-stack book browsing template built with Nuxt 4, Vue, Nitro, Drizzle ORM, and PostgreSQL. It takes the UCSD Book Graph Goodreads dataset (over two million books) and imports a curated 100,000-book subset into a Neon database, preserving Goodreads IDs and complete book metadata. It produces a searchable, paginated catalog with dynamically rendered catalog and book pages, plus JSON API routes for books, book counts, and individual book details. The project is maintained by Sébastien Chopin (atinux) on GitHub under the nuxt-books repository.

Key Features

  • Nuxt 4 stack — built on Nuxt 4 with Vue components and Nitro server routes, verified with pnpm typecheck, pnpm lint, and pnpm build.
  • Nitro cached handlers — the /api/books, /api/books/count, and /api/books/:id routes use defineCachedEventHandler with one-hour freshness, serving stale values while revalidating in the background; hashed keys derived from normalized filters, pagination, and book IDs let equivalent requests share a cache entry.
  • Header-only routeRules cache — catalog and book pages avoid ISR; a header-only cache marker exposes browser-cacheable _payload.json responses for client navigation without storing rendered pages in Nitro.
  • FastLink component — wraps <NuxtLink> and starts primary-button navigation on mousedown, while leaving modified clicks, keyboard navigation, and interactive descendants unchanged.
  • Keep-alive page state — <NuxtPage keepalive> retains catalog and book page instances across routes, so returning from a book restores loaded results and local page state.
  • Tiered prefetching — first-page catalog links prefetch on visibility, later pages on hover or focus; the first ten covers per catalog page use <NuxtImg preload>, and experimental.prefetchPreloadTags forwards destination cover hints as lower-priority rel="prefetch".
  • Accent-insensitive search — the PostgreSQL schema uses the unaccent extension for title search.
  • Neon subset importer — pnpm db:seed-neon selects the most-rated catalog-eligible books, inserts only referenced authors, and stops at a 400 MB soft storage limit (defaults import 100,000 books).

Who is it for?

  • Nuxt developers looking for a working reference of Nitro runtime caching, payload extraction, and prefetching in a real app rather than a docs snippet.
  • Data-heavy app builders who need to fit a large PostgreSQL catalog into a quota-limited hosted database like Neon's free tier.
  • Performance-focused engineers evaluating how visibility-based link prefetching and image preloading behave in practice, with a Playwright e2e suite covering payload navigation, prefetching, search cancellation, pagination warming, and scroll restoration.

What can you do with NuxtBooks?

  • Run a preview without a database: start the app without DATABASE_URL and it serves a generated preview catalog.
  • Import the full dataset: create the schema with pnpm db:migrate, download the UCSD gzip files, and run the author and book seeders, which read gzip directly and checkpoint large imports.
  • Shrink to a Neon subset: run pnpm db:seed-neon against a complete local catalog, overriding TARGET_BOOKS, TARGET_MAX_DATABASE_MB, or SOURCE_DATABASE_URL.
  • Test caching locally: cached handlers fall back to an in-memory storage driver during local development and e2e runs; only Vercel deployments use Runtime Cache under the nuxt-books:v1 namespace.

How does NuxtBooks work?

A request hits a Nitro cached handler keyed by normalized filter, pagination, or book ID; the response stays fresh for one hour, after which stale data is served while the entry refreshes. On the client, FastLink and visibility-based prefetching pull _payload.json responses and priority covers before navigation, and keep-alive retains page state on return.

Pros and cons

  • Cached API responses hold for one hour, so book data can be briefly stale by design.
  • prefetchPreloadTags is flagged as experimental and may change in a future Nuxt release.
  • The hosted catalog is a curated 100,000-book subset, not the full two-million-plus dataset.
  • Runtime Cache storage is only used on Vercel; local development uses an in-memory driver.

FAQ

Is NuxtBooks free to use?

Yes. The source is published on GitHub and the catalog is designed to fit within the free Neon database tier. The importer enforces a 400 MB soft storage limit by default to keep the subset inside that quota.

Does NuxtBooks use incremental static regeneration?

No. Catalog and book pages use a header-only routeRules cache marker instead, which exposes browser-cacheable _payload.json responses for client navigation without storing rendered pages in Nitro.

Which database does NuxtBooks need?

A PostgreSQL database, typically Neon connected through the Vercel Marketplace. DATABASE_URL is optional; without it the app serves a generated preview catalog, and POSTGRES_URL is still supported for existing environments.

What Node version does NuxtBooks require?

Node.js 22 or newer and pnpm. Setup uses pnpm install followed by pnpm dev, and end-to-end tests run with pnpm test:e2e against a production Nitro build.

Screenshot of NuxtBooks