> ## Documentation Index
> Fetch the complete documentation index at: https://docs.liteshop.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js

> Build a Next.js Site with the App Router and deploy its static export to Liteshop.

Liteshop hosts the static files a Next.js static export produces. This guide uses the App Router with `output: "export"`.

## Before you begin

* Install [Node.js](https://nodejs.org) 22 or later.
* Sign in to the [Liteshop dashboard](https://app.liteshop.me).

## Create the app

```sh theme={null}
npx create-next-app@latest my-site --yes --ts --app --no-tailwind --no-eslint
cd my-site
```

Replace `next.config.ts` to export static files:

```ts theme={null}
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "export",
  images: { unoptimized: true },
};

export default nextConfig;
```

This removes the template's `cacheComponents` and `partialPrefetching` options, because a static export can't use them. `images.unoptimized` lets `next/image` work without the image optimizer server. `next build` now writes the Site to `out/`.

## Add the manifest

Next.js copies everything in `public/` to the root of `out/`, so put `liteshop.json` there:

```json theme={null}
{
  "$schema": "https://docs.liteshop.me/schemas/site-v0.1.json",
  "specVersion": "0.1",
  "site": {
    "name": "My Site",
    "defaultLocale": "en",
    "supportedLocales": ["en"],
    "timezone": "Europe/Paris"
  },
  "frontend": {
    "entry": "index.html"
  },
  "capabilities": {
    "forms": [
      {
        "id": "contact",
        "name": { "en": "Contact" },
        "fields": [
          { "id": "email", "type": "email", "label": { "en": "Email" }, "required": true },
          { "id": "message", "type": "textarea", "label": { "en": "Message" }, "required": true }
        ]
      }
    ]
  }
}
```

Leave `capabilities` as `{}` if the Site has no Form. The [Site Bundle reference](https://docs.liteshop.me/reference/site-bundle.md) lists every field.

## Add the SDK

Install the Liteshop SDK:

```sh theme={null}
npm install @liteshop.ai/sdk
```

Import `liteshop` from it wherever the Site uses Forms, bookings or the catalogue. It calls the Site's own Liteshop endpoints and includes its TypeScript types.

`next dev` can't answer the SDK, because the package's dev plugin needs Vite. Test Forms on a deployed Site.

## Submit a Form

Put the form in a Client Component, for example `app/contact.tsx`, and render `<Contact />` from a page. Import the SDK and pass the Form ID as a literal string. Liteshop reads `liteshop.forms.submit("contact", ...)` from your built JavaScript to check that every declared Form has a handler.

```tsx theme={null}
"use client";

import { useState, type FormEvent } from "react";
import { liteshop } from "@liteshop.ai/sdk";

export default function Contact() {
  const [status, setStatus] = useState<"idle" | "sent" | "error">("idle");

  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = event.currentTarget;
    const data = new FormData(form);
    try {
      await liteshop.forms.submit("contact", {
        email: String(data.get("email")),
        message: String(data.get("message")),
      });
      form.reset();
      setStatus("sent");
    } catch {
      setStatus("error");
    }
  }

  return (
    <form onSubmit={submit}>
      <label>Email <input name="email" type="email" required /></label>
      <label>Message <textarea name="message" required /></label>
      <button type="submit">Send</button>
      {status === "sent" && <p>Thanks, your message was sent.</p>}
      {status === "error" && <p>Your message could not be sent. Try again.</p>}
    </form>
  );
}
```

Don't add `method="post"` or an `action` to the form. See the [Forms reference](https://docs.liteshop.me/reference/forms.md) for field types and the anti-spam field.

## Build and package the Site

```sh theme={null}
npm run build
cd out
zip -r ../site.zip .
```

The ZIP must have `index.html` and `liteshop.json` at its root, which zipping the contents of `out` gives you.

## Upload the Site

To publish a new Site:

1. In the [Liteshop dashboard](https://app.liteshop.me), click **Website** > **Upload files**.
2. Enter the Site name and subdomain, and select `site.zip`.
3. Click **Check and publish**.

To update a Site, open **Website settings** (the gear button on the **Website** page), and upload the new ZIP file in **Upload an update**. An update's `liteshop.json` must name the live version in `baseDeployment`. If the value is missing or out of date, validation fails, and its repair message gives the exact value to set in `public/liteshop.json`. For details, see [Publish and manage a Site](https://docs.liteshop.me/develop/deploy.md).

## Routing

Liteshop serves `/about` from `about.html`, and from `about/index.html` by redirecting to `/about/`. With the default `trailingSlash: false`, Next.js writes `app/about/page.tsx` to `about.html` and links to `/about`, so every exported page works on reload. `next/link` navigation also loads the `.txt` files the export writes next to each page; keep them in the ZIP.

Dynamic routes need `generateStaticParams` so each page is exported as its own HTML file. To show the exported `404.html` for unknown paths, set `"notFound": "404.html"` under `frontend` in `liteshop.json`.

## What runs on Liteshop

Liteshop hosts static output only: no server rendering, Route Handlers that read the request, Server Actions, Proxy (middleware), Incremental Static Regeneration or the default image optimizer. The Site's security policy blocks scripts, styles and network requests to other origins, frames, workers and `eval`. Validation warns when your build appears to use one of those features, and fails on external scripts and frames. The Next.js runtime mentions `fetch`, so every Next.js build gets that warning; you can ignore it if your own code doesn't call `fetch`.

## Dashboard edits

Site Owners can edit catalogue items, collections, and stock in the dashboard, which publishes a new Deployment from your files without rebuilding your app. Read the catalogue in the browser with `liteshop.catalogue.list()`. Don't import `liteshop.json` or render catalogue items at build time; otherwise, dashboard edits don't appear on the Site until you rebuild and upload it again. See the [Catalogue reference](https://docs.liteshop.me/reference/catalogue.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.