<p align="center">
<a href="https://commerce.nuxt.dev" target="_blank" rel="noopener">
<img alt="NuxtCommerce β Headless storefront for WooCommerce" src="https://github.com/user-attachments/assets/1c6720b7-5aea-4f6b-be55-8944fb81799a">
</a>
</p>
<h1 align="center">NuxtCommerce</h1>
<p align="center">
Modern, open-source headless storefront for WooCommerce β built with <strong>Nuxt 4</strong> & <strong>GraphQL</strong>.<br/>
Pinterest-style UI, dark mode, multi-language, and a DX focused, production-ready setup.
<br/><br/>
<a href="https://commerce.nuxt.dev"><strong>π Live Demo</strong></a>
<br/><br/>
<a href="https://github.com/zackha/nuxtcommerce/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/zackha/nuxtcommerce?style=flat&color=ff4757"></a>
<a href="https://github.com/zackha/nuxtcommerce/issues"><img alt="Issues" src="https://img.shields.io/github/issues/zackha/nuxtcommerce?style=flat"></a>
<img alt="Built with Nuxt" src="https://img.shields.io/badge/Nuxt-238636?logo=nuxt&logoColor=white&style=flat"/>
<img alt="GraphQL" src="https://img.shields.io/badge/GraphQL-E10098?logo=graphql&logoColor=white&style=flat"/>
<img alt="WooCommerce" src="https://img.shields.io/badge/WooCommerce-96588A?logo=woo&logoColor=white&style=flat"/>
</p>
## Table of Contents
* [Features](#features)
* [Tech Stack](#tech-stack)
* [Quickstart](#quickstart)
* [Configuration](#configuration)
* [WordPress + WooCommerce + WPGraphQL Setup](#wordpress--woocommerce--wpgraphql-setup)
* [Architecture Overview](#architecture-overview)
* [API Endpoints (Server)](#api-endpoints-server)
* [Internationalization (i18n)](#internationalization-i18n)
* [Performance & Caching](#performance--caching)
* [Contributors & Acknowledgements](#-contributors--acknowledgements)
* [Contact](#contact)
## Features
* π― **Headless WooCommerce** store powered by **WPGraphQL** (+ WooGraphQL)
* β‘οΈ **Nuxt 4 + Nitro** with server-side GraphQL proxy, **SWR** caching & route rules
* π§ **Pinterest-style product grid** with **infinite scroll**
* π **Cart & Checkout** (WooCommerce session cookie handled server-side)
* β€οΈ **Wishlist** (localStorage) & **Favorites** page
* π **Dark mode** + sleek micro-interactions (skeletons, transitions)
* π **Multi-language** (en, nb, nl, de) via `@nuxtjs/i18n`
* πΌοΈ Optimized images with `@nuxt/image`
* π Friendly toasts with **Notivue**
* π Good **SEO defaults** + **JSON-LD Product schema**
* βοΈ Ready for **NuxtHub** / Cloudflare Workers (KV cache)
## Tech Stack
* **Framework:** Nuxt 4, Vue 3
* **GraphQL Client (server):** `graphql-request` (`GraphQLClient` + `gql`)
* **Styling/UI:** Tailwind CSS, `@nuxt/ui`, Icons (Iconify)
* **Images:** `@nuxt/image`
* **i18n:** `@nuxtjs/i18n`
* **Toasts:** `notivue`
* **Deployment (optional):** NuxtHub + Cloudflare Workers
> Project scripts live in `package.json` (`dev`, `dev:ssl`, `build`, `generate`, `preview`, `deploy`).
## Quickstart
### Requirements
* **Node.js** `>= 18.20` (or 20.x)
* **pnpm** (project uses `[email protected]`)
* A WordPress backend with WooCommerce + WPGraphQL (see setup below)
### 1) Clone & install
```bash
git clone https://github.com/zackha/nuxtcommerce.git
cd nuxtcommerce
pnpm install
```
### 2) Configure environment
Create `.env`:
```bash
GQL_HOST=https://your-woocommerce-site.com/graphql
```
### 3) Run
```bash
pnpm run dev
# optional HTTPS local dev
pnpm run dev:ssl
```
App runs at **[http://localhost:3000](http://localhost:3000)**
### 4) Build / Preview
```bash
pnpm run build
pnpm run preview
```
## Configuration
Key settings are in **`nuxt.config.ts`**:
* **Runtime Config:** `runtimeConfig.gqlHost` (reads `GQL_HOST`)
* **Modules:** `@nuxt/ui`, `@nuxt/image`, `@nuxtjs/i18n`, `notivue/nuxt`, `@nuxthub/core`
* **Route Rules:** SWR caching for `/categories` and `/favorites`, prerender for `/`
* **Nitro Prerender:** `/sitemap.xml`, `/robots.txt`
* **NuxtHub Cache:** `hub: { cache: true }` (optional KV cache)
## WordPress + WooCommerce + WPGraphQL Setup
> This project uses **WordPress + WooCommerce** as the headless backend and **WPGraphQL** (+ WooGraphQL) as the API layer consumed by the Nuxt app. Follow the steps below carefully.
### 1) Fresh WordPress install (quick checklist)
1. Install WordPress on your host (or local with e.g. Local, MAMP, Docker).
2. Log in to `/wp-admin`.
3. Go to **Settings β General** and set:
* Site Language, Timezone, Date/Time format
* Ensure **WordPress Address** and **Site Address** use **https\://** in production
4. Go to **Settings β Permalinks** and choose **Post name**.
> Pretty permalinks are required for `/graphql`.
### 2) Required plugins
Install and activate:
* [**WooCommerce**](https://woocommerce.com/) β core e-commerce
* [**WPGraphQL**](https://www.wpgraphql.com/) β GraphQL API for WordPress
* [**WPGraphQL WooCommerce (WooGraphQL)**](https://woographql.com/) β WooCommerce schema for WPGraphQL
* *(Optional)* Regenerate Thumbnails β rebuild image sizes after changes
### 3) WooCommerce onboarding
* **General:** Store address, selling/shipping regions, currency (NOK/EUR/USDβ¦)
* **Products:** Reviews on/off, measurements
* **Tax:** Enable and define rates (if applicable)
* **Shipping:** Create at least one zone + method (e.g., Flat rate)
* **Payments:** Enable **Cash on Delivery** (COD) for quick E2E testing
* **Accounts & Privacy:** Decide guest checkout
* **Advanced:** REST is not required; GraphQL is separate
> Demo checkout posts `paymentMethod: 'cod'` β ensure COD is enabled for testing.
### 4) Product attributes & taxonomies (used in GraphQL)
Create attributes in **Products β Attributes**:
* **Color** (`slug: color` β taxonomy `pa_color`) β used via `allPaColor`
* **Style** (`slug: style` β taxonomy `pa_style`) β used via `allPaStyle`
Add terms (e.g., Color: Red/Blue/Black; Style: Casual/Sport).
### 5) Import products (CSV) or create manually
**CSV Import (recommended for demo)**
1. Download [`public/products.zip`](https://github.com/zackha/nuxtcommerce/raw/refs/heads/master/public/products.zip) from the repo.
2. **Products β Import**, upload CSV(s), map columns:
* **variable** for parent products
* Attributes β `pa_color`, `pa_style`.
* Variations CSV must reference correct parent
3. Ensure products are **Published**, **In Stock**, with prices.
**Manual**
* Variable product β add attributes (used for variations) β create variations from attributes β set price/stock β set images.
### 6) Media sizes (thumbnails & large)
Frontend queries use:
* `WOOCOMMERCE_THUMBNAIL`
* `LARGE`
Check sizes in **WooCommerce** (thumbnails) & **Settings β Media** (large).
If you tweak sizes or bulk import images, run **Regenerate Thumbnails**.
### 7) Connect frontend β backend
Create `.env` in the Nuxt project:
```bash
GQL_HOST=https://your-woocommerce-site.com/graphql
```
This is read by `runtimeConfig.gqlHost` and used by the server utility that proxies & caches GraphQL calls.
## Architecture Overview
```
/app
ββ app.vue # Global head/meta + header/footer + Notivue
ββ app.config.ts # Site name/description, UI theme
ββ pages/
β ββ index.vue # Product grid, infinite scroll, filters
β ββ categories.vue # Category grid
β ββ favorites.vue # Wishlist page
β ββ product/[id].vue # Product detail, gallery, variations, schema.org
ββ components/ # UI building blocks (cards, carousels, cart, checkout...)
ββ composables/ # useCart, useCheckout, useWishlist, useComponents
ββ gql/ # GraphQL queries & mutations
/server
ββ api/
β ββ products.get.ts # GET products (cursor pagination) β cached (SWR)
β ββ product.get.ts # GET product detail β cached (SWR)
β ββ search.get.ts # GET search (top 6) β cached (SWR)
β ββ categories.get.ts # GET categories β cached (SWR)
β ββ cart/add.post.ts # POST add to cart (Woo session cookie handling)
β ββ cart/update.post.ts # POST update quantities / remove
β ββ checkout.post.ts # POST checkout (COD demo)
ββ routes/
β ββ sitemap.xml.ts # Minimal sitemap
β ββ robots.txt.ts # Robots
ββ utils/wpgraphql.ts # GraphQL client + error wrapper + Woo session cookie
```
**Flow:**
Client (`$fetch` to `/api/*`) β Nitro server proxies to WPGraphQL β GET endpoints are cached (SWR); POST endpoints manage the WooCommerce session cookie.
## API Endpoints (Server)
* `GET /api/products?search=&category=&orderby=DESC|ASC&fieldby=DATE|PRICE&after=...`
* `GET /api/product?slug=:slug&sku=:skuFragment`
* `GET /api/search?search=:q` (first 6)
* `GET /api/categories`
* `POST /api/cart/add` `{ productId }`
* `POST /api/cart/update` `{ items: [{ key, quantity }] }`
* `POST /api/checkout` `{ billing: {...}, paymentMethod: 'cod' }`
## Internationalization (i18n)
* Locales: **en-GB**, **nb-NO**, **nl-NL**, **de-DE**
* Default: **en**
* Use `useLocalePath()` for links; SEO tags adapt per route.
## Performance & Caching
* **`cachedEventHandler`** on GET handlers with **SWR** (stale-while-revalidate)
* **Route Rules** for `/categories` and `/favorites`
* Optional **NuxtHub KV cache** (`hub: { cache: true }`)
* Image optimization via `@nuxt/image`
* Prerender: `/`, `/sitemap.xml`, `/robots.txt`
## π Contributors & Acknowledgements
We sincerely thank everyone who has contributed to **NuxtCommerce**.
Your support, feedback, and ideas keep this project moving forward. π
β¨ **Special thanks**
| Collaborator |
| :----------------------------------------------------------------------------------------------------------------: |
| [<img src="https://github.com/rikp777.png?size=115" width=115><br><sub>@rikp777</sub>](https://github.com/rikp777) |
<sub>More contributors will be highlighted here as the project grows.</sub>
## Contact
Have questions or suggestions?
* Email: **[[email protected]](mailto:[email protected])**
* X (Twitter): [**@ZHatlen**](https://twitter.com/ZHatlen)
> **Note**
> You can view the orders you create during the live demo at [NuxtCommerce Admin](https://nuxtcommerce-admin.vercel.app/).
> From there, you can also update their statuses and add notes to your orders.