---
title: "Slice Machine"
description: "A reference for existing Slice Machine projects. Slice Machine is deprecated. New projects use the Type Builder and the Prismic CLI."
category: "concepts"
audience: developers
lastUpdated: "2026-09-17T03:24:45.000Z"
---

Slice Machine is a local tool for [content modeling](https://prismic.io/docs/content-modeling.md). It runs in your website project. You build [page types](https://prismic.io/docs/content-modeling.md#page-types), [custom types](https://prismic.io/docs/content-modeling.md#custom-types), and [slices](https://prismic.io/docs/slices.md) in it, then push them to Prismic.

> **Caution**
>
> Slice Machine is deprecated. It is replaced by the [Type Builder](https://prismic.io/docs/type-builder.md) and the [Prismic CLI](https://prismic.io/docs/cli.md). Existing projects still work. New projects must use the Type Builder. To move a project, see [Migrate to the Type Builder](#migrate-to-the-type-builder).

This page is a reference for existing projects. It assumes that you know [content modeling](https://prismic.io/docs/content-modeling.md) and [slices](https://prismic.io/docs/slices.md).

# Migrate to the Type Builder

The [Type Builder](https://prismic.io/docs/type-builder.md) models content in the browser. The [Prismic CLI](https://prismic.io/docs/cli.md) syncs models to your project, generates TypeScript types, and writes component files. Together they replace Slice Machine, a local app that you operate by hand.

They also work with AI tools. An agent can model content and write components with the CLI while you review the result in the Type Builder.

The migration takes a few minutes and is mostly automated.

1. **Push local changes**

   If you have unpushed changes in Slice Machine, push them first. Start Slice Machine, click **Review changes**, and then click **Push**.

   > **Important**
   >
   > You will lose local changes that are not committed in Git or pushed to Prismic.

2. **Install the skill**

   If you use an AI tool like Claude Code, Codex, or Cursor, install the Prismic skill. It teaches your agent the [Prismic CLI](https://prismic.io/docs/cli.md).

   ```sh
   npx skills add --global --yes prismicio/skills
   ```

3. **Run the automatic migration**

   Run the CLI's `init` command in your project.

   ```sh
   npx prismic init
   ```

   The command:

   * Replaces `slicemachine.config.json` with `prismic.config.json`.
   * Pulls models from Prismic into your project.
   * Uninstalls Slice Machine and your project's adapter.

   You can now model content in the [Type Builder](https://prismic.io/docs/type-builder.md).

The rest of this page describes how to use Slice Machine in an existing project.

# Run Slice Machine

Slice Machine is the [`slice-machine-ui`](https://prismic.io/docs/technical-reference/slice-machine-ui.md) package in your project. Open it from your project:

```sh
npx start-slicemachine --open
```

It opens in your browser at `http://localhost:9999`.

# Model content

Slice Machine saves model changes to files in your project. Content writers see them after you [push them to Prismic](#push-changes-to-prismic).

Every type, slice, variation, and field has a **name** (or **label**) that content writers see in the [Page Builder](https://prismic.io/docs/guides/page-builder.md), and an **ID** (or **API ID**) used in the Content API. Use a clear name and a short, snake-cased ID unless noted.

## Create a page type or custom type

[Page types](https://prismic.io/docs/content-modeling.md#page-types) describe the pages of your website. [Custom types](https://prismic.io/docs/content-modeling.md#custom-types) describe content that is not a page, like website settings or a navigation menu.

1. **Create the type**

   In Slice Machine, open **Page types** or **Custom types** from the sidebar. Click the **Create** button in the top-right corner.

   In the modal, choose the kind of type:

   * **Reusable type**: Content writers can publish many documents of this type. For example, a product page or an author.
   * **Single type**: Content writers can publish one document of this type. For example, a homepage or website settings.

   Then set the name and ID.

2. **Add slices to a page type**

   In the **Slices** section, click the **Add** button. From the menu, you can create a new slice, add a built-in template, or add an existing slice.

   Slices are intended for page types and should be avoided in custom types. To add them anyway, enable slices with the toggle in the **Slices** section.

3. **Add fields**

   Add fields to the **static zone**. In a page type, use it for fields that do not belong in a slice. They appear at the top of the page in the Page Builder.

4. **Push to Prismic**

   [Push your changes](#push-changes-to-prismic) when the type is ready.

5. **Create a page file**

   For a page type, create a page file at the page's path. The **Page snippet** button in the top-right corner of Slice Machine gives you this file with your page type's ID filled in.

   This example displays a **Page** page type at `/:uid`.

   * **Next.js:**

     ```tsx filename=app/[uid]/page.tsx collapsed
     import type { Metadata } from "next";
     import { SliceZone } from "@prismicio/react";
     import { createClient } from "@/prismicio";
     import { components } from "@/slices";

     export default async function Page({ params }: PageProps<"/[uid]">) {
       const { uid } = await params;
       const client = createClient();
       const page = await client.getByUID("page", uid);

       return <SliceZone slices={page.data.slices} components={components} />;
     }

     export async function generateMetadata({
       params,
     }: PageProps<"/[uid]">): Promise<Metadata> {
       const { uid } = await params;
       const client = createClient();
       const page = await client.getByUID("page", uid);

       return {
         title: page.data.meta_title,
         description: page.data.meta_description,
         openGraph: {
           images: [{ url: page.data.meta_image.url ?? "" }],
         },
       };
     }

     export async function generateStaticParams() {
       const client = createClient();
       const pages = await client.getAllByType("page");

       return pages.map((page) => ({ uid: page.uid }));
     }
     ```

   * **Next.js (Pages Router):**

     ```tsx filename=pages/[uid].tsx collapsed
     import type { InferGetStaticPropsType, GetStaticPropsContext } from "next";
     import { SliceZone } from "@prismicio/react";
     import { createClient } from "@/prismicio";
     import { components } from "@/slices";

     type Params = { uid: string };

     // Fetch page data at build time.
     export async function getStaticProps({
       params,
       previewData,
     }: GetStaticPropsContext<Params>) {
       const client = createClient({ previewData });
       const page = await client.getByUID("page", params.uid);

       return { props: { page } };
     }

     // Display the page's slices.
     export default function Page({
       page,
     }: InferGetStaticPropsType<typeof getStaticProps>) {
       return <SliceZone slices={page.data.slices} components={components} />;
     }

     // Generate all pages statically.
     export async function getStaticPaths() {
       const client = createClient();
       const pages = await client.getAllByType("page");

       return {
         paths: pages.map((page) => ({ params: { uid: page.uid } })),
         fallback: false,
       };
     }
     ```

   * **Nuxt:**

     ```vue filename=pages/[uid].vue collapsed
     <script setup lang="ts">
     import { components } from "~/slices";

     const prismic = usePrismic();
     const route = useRoute();
     const { data: page } = await useAsyncData(route.params.uid as string, () =>
       prismic.client.getByUID("page", route.params.uid as string),
     );

     useSeoMeta({
       title: page.value?.data.meta_title ?? undefined,
       description: page.value?.data.meta_description ?? undefined,
       ogImage: computed(() => prismic.asImageSrc(page.value?.data.meta_image)),
     });
     </script>

     <template>
       <main>
         <SliceZone :slices="page?.data.slices ?? []" :components="components" />
       </main>
     </template>
     ```

   * **SvelteKit:**

     ```ts filename=src/routes/[[preview=preview]]/[uid]/+page.server.ts collapsed
     import type { PageServerLoad, EntryGenerator } from "./$types";
     import { createClient } from "$lib/prismicio";

     export const load: PageServerLoad = async ({ params, fetch, cookies }) => {
       const client = createClient({ fetch, cookies });
       const page = await client.getByUID("page", params.uid);

       return { page };
     };

     export const entries: EntryGenerator = async () => {
       const client = createClient();
       const pages = await client.getAllByType("page");

       return pages.map((page) => ({ uid: page.uid }));
     };
     ```

     ```svelte filename=src/routes/[[preview=preview]]/[uid]/+page.svelte collapsed
     <script lang="ts">
       import { isFilled, asImageSrc } from "@prismicio/client";
       import { SliceZone } from "@prismicio/svelte";
       import { components } from "$lib/slices";
       import type { PageProps } from "./$types";

       const { data }: PageProps = $props();
     </script>

     <svelte:head>
       <title>{data.page.data.meta_title}</title>
       {#if isFilled.keyText(data.page.data.meta_description)}
         <meta name="description" content={data.page.data.meta_description} />
       {/if}
       {#if isFilled.image(data.page.data.meta_image)}
         <meta property="og:image" content={asImageSrc(data.page.data.meta_image)} />
       {/if}
     </svelte:head>

     <SliceZone slices={data.page.data.slices} {components} />
     ```

6. **Add a route**

   For a page type, add a route to the [Prismic client](#prismic-client) so that Prismic can build URLs for its pages.

## Create a slice

[Slices](https://prismic.io/docs/slices.md) are the reusable sections of a page.

1. **Create the slice**

   In Slice Machine, open **Slices** from the sidebar. Click the **Create** button in the top-right corner.

   Use a pascal-cased **slice name**. It is also the component name in your code.

   The **target library** is the [slice library](#slice-libraries) that stores the slice.

2. **Add fields**

   Click the **Add a field** button to add fields to the slice.

3. **Add a screenshot**

   Screenshots help content writers select the correct slice.

   Take a screenshot of the slice's design. Then click the "**...**" button and select **Update screenshot**.

4. **Write the slice component**

   Slice Machine generates a basic component in the slice library. Edit it to display the slice's content.

   This example displays a **Call to Action** slice with a rich text field and a link field.

   * **Next.js:**

     ```tsx filename=src/slices/CallToAction/index.tsx
     import type { Content } from "@prismicio/client";
     import { PrismicRichText, type SliceComponentProps } from "@prismicio/react";
     import { PrismicNextLink } from "@prismicio/next";

     type CallToActionProps = SliceComponentProps<Content.CallToActionSlice>;

     export default function CallToAction({ slice }: CallToActionProps) {
       return (
         <section className="flex flex-col gap-4 p-8">
           <PrismicRichText field={slice.primary.text} />
           <PrismicNextLink field={slice.primary.link} className="button" />
         </section>
       );
     }
     ```

   * **Nuxt:**

     ```vue filename=slices/CallToAction/index.vue
     <script setup lang="ts">
     import type { Content } from "@prismicio/client";

     defineProps(getSliceComponentProps<Content.CallToActionSlice>());
     </script>

     <template>
       <section class="flex flex-col gap-4 p-8">
         <PrismicRichText :field="slice.primary.text" />
         <PrismicLink :field="slice.primary.link" class="button" />
       </section>
     </template>
     ```

   * **SvelteKit:**

     ```svelte filename=src/lib/slices/CallToAction/index.svelte collapsed
     <script lang="ts">
       import type { Content } from "@prismicio/client";
       import {
         PrismicRichText,
         PrismicLink,
         type SliceComponentProps,
       } from "@prismicio/svelte";

       type Props = SliceComponentProps<Content.CallToActionSlice>;

       let { slice }: Props = $props();
     </script>

     <section class="flex flex-col gap-4 p-8">
       <PrismicRichText field={slice.primary.text} />
       <PrismicLink field={slice.primary.link} class="button" />
     </section>
     ```

   The [Fields](https://prismic.io/docs/fields.md) guides show how to display each field type.

5. **Add the slice to a page type**

   Content writers can only use a slice that belongs to a page type.

   Open the page type from the sidebar. In the **Slices** section, click the **Add** button and choose **Select existing**. Then enable your slice and click **Add**.

6. **Push to Prismic**

   [Push your changes](#push-changes-to-prismic) when the slice and page type are ready.

## Add a slice variation

A [variation](https://prismic.io/docs/slices.md#slice-variations) is an alternative version of a slice with its own fields and screenshot.

1. **Add a variation**

   In Slice Machine, open the slice. In the section next to the slice's fields, click the **Add a variation** button.

   Set the name and a camel-cased **variation ID**. **Duplicate from** copies an existing variation as a starting point.

2. **Add a screenshot**

   Take a screenshot of the variation's design. Then click the "**...**" button and select **Update screenshot**.

3. **Update the slice component**

   Read the slice's `variation` property to display each variation.

   ```ts
   if (slice.variation === "withButton") {
     // Display the "With Button" variation.
   } else {
     // Display the default variation.
   }
   ```

4. **Push to Prismic**

   [Push your changes](#push-changes-to-prismic) when the variation is ready.

## Add a field

[Fields](https://prismic.io/docs/fields.md) hold the content of your types and slices.

1. **Add the field**

   In Slice Machine, open the page type, custom type, or slice. Click the **Add a field** button and select a field type. Then set the label and API ID.

2. **(Optional) Configure the field**

   Field settings depend on the field type. For example:

   * **Boolean**: Set a default value and custom labels for `true` and `false`.
   * **Image**: Add responsive sizes with fixed dimensions.
   * **Rich text**: Choose the permitted formatting options under **Accept**. Allow links to open in a new window and allow multiple paragraphs.
   * **Content relationship**: Restrict the field to a page type with **Add type**. Then select the fields to include in the API response, up to two levels deep. Slice Machine adds the selected fields to the generated TypeScript types.

   Integration fields and rich text labels are not in the Slice Machine UI. Add them in the [model files](#model-files).

   The **Show code snippets** toggle above the fields shows how to display each field in your framework.

3. **Push to Prismic**

   [Push your changes](#push-changes-to-prismic) when the field is ready.

## Push changes to Prismic

> **Important**
>
> A push can change or remove existing content. Learn about the [impact of pushing changes](https://prismic.io/docs/content-modeling.md#impact-of-pushing-changes) before you push to production.

Click **Review changes** in the sidebar. If the changes are correct, click the **Push** button in the top-right corner.

The Page Builder now recognizes your changes.

# Simulate slices

The slice simulator shows a live view of a slice while you write its component. It runs off the [slice simulator page](#slice-simulator-page) in your website.

1. **Start your website's development server**

   The simulator runs off your development server.

2. **Open the simulator**

   In Slice Machine, open the slice. Click the **Simulate** button in the top-right corner.

3. **Write the slice component**

   Edit the slice's component. The simulator updates when you save. Fill in content with the mock editor to the right. The **Editor** toggle in the top-right corner shows or hides it.

Slice Machine loads the simulator from `localSliceSimulatorURL` in [`slicemachine.config.json`](#slicemachineconfigjson). The Page Builder loads it from the [slice simulator URL](https://prismic.io/docs/previews.md#set-up-previews) stored in your repository.

# Project files

`@slicemachine/init` created these files when the project was set up. Each entry describes one file, what it does, and its code for each framework.

## slicemachine.config.json

The Slice Machine configuration file, in the root of your project.

```json filename=slicemachine.config.json
{
  "repositoryName": "example-prismic-repo",
  "adapter": "@slicemachine/adapter-next",
  "libraries": ["./src/slices"],
  "localSliceSimulatorURL": "http://localhost:3000/slice-simulator"
}
```

| Parameter              | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                          | Default |
| ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| repositoryName         | string    | The Prismic repository domain for the project. Always use the production repository.                                                                                                                                                                                                                                                                                                                                                                 | None    |
| adapter                | string    | The project's adapter: [`@slicemachine/adapter-next`](https://prismic.io/docs/technical-reference/slicemachine-adapter-next.md), [`@slicemachine/adapter-nuxt`](https://prismic.io/docs/technical-reference/slicemachine-adapter-nuxt.md), or [`@slicemachine/adapter-sveltekit`](https://prismic.io/docs/technical-reference/slicemachine-adapter-sveltekit.md). It generates framework-specific files, like slice components and TypeScript types. | None    |
| libraries              | string\[] | The [slice libraries](#slice-libraries) in the project.                                                                                                                                                                                                                                                                                                                                                                                              | None    |
| localSliceSimulatorURL | string    | The full URL of the local [slice simulator page](#slice-simulator-page).                                                                                                                                                                                                                                                                                                                                                                             | None    |

To configure the adapter, replace the `adapter` string with an object and add options:

```json filename=slicemachine.config.json {5-8}
{
  "repositoryName": "example-prismic-repo",
  "libraries": ["./src/slices"],
  "localSliceSimulatorURL": "http://localhost:3000/slice-simulator",
  "adapter": {
    "resolve": "@slicemachine/adapter-next",
    "options": { "typescript": true }
  }
}
```

| Property                               | Type    | Description                                                                                                                                   | Default                                                            |
| -------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| format (optional)                      | boolean | Determines if generated files are formatted using [Prettier](https://prettier.io/).                                                           | `true`                                                             |
| typescript (optional)                  | boolean | Determines if generated files are written in TypeScript or JavaScript.                                                                        | `true` if a project has a `tsconfig.json` file, `false` otherwise. |
| lazyLoadSlices (optional)              | boolean | Determines if slice components are lazy loaded. Next.js and Nuxt only.                                                                        | `true`                                                             |
| jsxExtension (optional)                | boolean | Determines if generated JavaScript files use a `.jsx` file extension. Has no effect when TypeScript is used. Next.js only.                    | `false`                                                            |
| generatedTypesFilePath (optional)      | string  | The filepath at which [generated TypeScript types](#generated-typescript-types) are saved. SvelteKit projects use `src/prismicio-types.d.ts`. | `prismicio-types.d.ts`                                             |
| environmentVariableFilePath (optional) | string  | The filepath at which the active [environment](#environments) is stored as an environment variable.                                           | `.env.local`                                                       |

## Prismic client

The file that creates the Prismic client. It reads the repository name from `slicemachine.config.json`, defines the [routes](https://prismic.io/docs/routes.md) that Prismic uses to build URLs, and enables previews.

* **Next.js:**

  ```ts filename=prismicio.ts collapsed
  import {
    createClient as baseCreateClient,
    type ClientConfig,
    type Route,
  } from "@prismicio/client";
  import { enableAutoPreviews } from "@prismicio/next";
  import sm from "../slicemachine.config.json";

  export const repositoryName = sm.repositoryName;

  // `type` is the API ID of a page type.
  // `path` determines the URL for a page of that type.
  const routes: Route[] = [
    { type: "homepage", path: "/" },
    { type: "page", path: "/:uid" },
    { type: "blog_post", path: "/blog/:uid" },
  ];

  export function createClient(config: ClientConfig = {}) {
    const client = baseCreateClient(repositoryName, {
      routes,
      fetchOptions: {
        next: { tags: ["prismic"] },
        cache: "force-cache",
      },
      ...config,
    });

    enableAutoPreviews({ client });

    return client;
  }
  ```

  `fetchOptions` tags every Prismic request with `prismic` and caches it until the [revalidation route](#content-change-webhook) clears the tag.

* **Next.js (Pages Router):**

  ```ts filename=prismicio.ts collapsed
  import {
    createClient as baseCreateClient,
    type ClientConfig,
    type Route,
  } from "@prismicio/client";
  import {
    enableAutoPreviews,
    type CreateClientConfig,
  } from "@prismicio/next/pages";
  import sm from "../slicemachine.config.json";

  export const repositoryName = sm.repositoryName;

  // `type` is the API ID of a page type.
  // `path` determines the URL for a page of that type.
  const routes: Route[] = [
    { type: "homepage", path: "/" },
    { type: "page", path: "/:uid" },
    { type: "blog_post", path: "/blog/:uid" },
  ];

  export function createClient({
    req,
    previewData,
    ...config
  }: CreateClientConfig = {}) {
    const client = baseCreateClient(repositoryName, {
      routes,
      ...config,
    });

    enableAutoPreviews({ client, req, previewData });

    return client;
  }
  ```

* **Nuxt:**

  `@nuxtjs/prismic` creates the client. Configure it in `nuxt.config.ts`.

  ```ts filename=nuxt.config.ts collapsed
  export default defineNuxtConfig({
    modules: ["@nuxtjs/prismic"],
    prismic: {
      endpoint: "example-prismic-repo",
      clientConfig: {
        // `type` is the API ID of a page type.
        // `path` determines the URL for a page of that type.
        routes: [
          { type: "homepage", path: "/" },
          { type: "page", path: "/:uid" },
          { type: "blog_post", path: "/blog/:uid" },
        ],
      },
    },
  });
  ```

* **SvelteKit:**

  ```ts filename=src/lib/prismicio.ts collapsed
  import {
    createClient as baseCreateClient,
    type Route,
  } from "@prismicio/client";
  import {
    enableAutoPreviews,
    type CreateClientConfig,
  } from "@prismicio/svelte/kit";
  import sm from "../../slicemachine.config.json";

  export const repositoryName = sm.repositoryName;

  // `type` is the API ID of a page type.
  // `path` determines the URL for a page of that type.
  const routes: Route[] = [
    { type: "homepage", path: "/" },
    { type: "page", path: "/:uid" },
    { type: "blog_post", path: "/blog/:uid" },
  ];

  export function createClient({ cookies, ...config }: CreateClientConfig = {}) {
    const client = baseCreateClient(repositoryName, {
      routes,
      ...config,
    });

    enableAutoPreviews({ client, cookies });

    return client;
  }
  ```

Each route's `path` must match a page file. For example, `/blog/:uid` is `app/blog/[uid]/page.tsx` in Next.js, `pages/blog/[uid].vue` in Nuxt, and `src/routes/[[preview=preview]]/blog/[uid]/+page.svelte` in SvelteKit. The [Routes](https://prismic.io/docs/routes.md) guide lists the path keywords.

To make the repository private, run `npx prismic repo set-api-access private` and create an access token with `npx prismic token create`. Save the token as `PRISMIC_ACCESS_TOKEN` in `.env` and pass it to the client as `accessToken`. The token is a secret. Do not use it in client-side code.

## Slice simulator page

The page that Slice Machine and the Page Builder load in an iframe to render one slice at a time.

* **Next.js:**

  ```tsx filename=app/slice-simulator/page.tsx collapsed
  import {
    SliceSimulator,
    SliceSimulatorParams,
    getSlices,
  } from "@prismicio/next";
  import { SliceZone } from "@prismicio/react";
  import { components } from "@/slices";

  export default async function SliceSimulatorPage({
    searchParams,
  }: SliceSimulatorParams) {
    const { state } = await searchParams;
    const slices = getSlices(state);

    return (
      <SliceSimulator>
        <SliceZone slices={slices} components={components} />
      </SliceSimulator>
    );
  }
  ```

* **Next.js (Pages Router):**

  ```tsx filename=pages/slice-simulator.tsx
  import { SliceSimulator } from "@slicemachine/adapter-next/simulator";
  import { SliceZone } from "@prismicio/react";
  import { components } from "@/slices";

  export default function SliceSimulatorPage() {
    return (
      <SliceSimulator
        sliceZone={(props) => <SliceZone {...props} components={components} />}
      />
    );
  }
  ```

* **Nuxt:**

  ```vue filename=pages/slice-simulator.vue
  <script setup lang="ts">
  import { components } from "~/slices";
  </script>

  <template>
    <SliceSimulator v-slot="{ slices }">
      <SliceZone :slices="slices" :components="components" />
    </SliceSimulator>
  </template>
  ```

* **SvelteKit:**

  ```svelte filename=src/routes/slice-simulator/+page.svelte
  <script>
    import { SliceSimulator, SliceZone } from "@prismicio/svelte";
    import { components } from "$lib/slices";
  </script>

  <SliceSimulator let:slices>
    <SliceZone {slices} {components} />
  </SliceSimulator>
  ```

Your repository stores the URL of this page as its slice simulator URL. Set it with the Prismic CLI, then update it to your production domain after you deploy. You can also set it in the Page Builder under **Live preview settings**.

```sh
npx prismic preview set-simulator http://localhost:3000
```

## Preview routes

The files that let content writers preview draft content on your website. `<PrismicPreview>` adds the Prismic toolbar, `enableAutoPreviews()` in the [Prismic client](#prismic-client) fetches drafts during a preview, and the `/api/preview` route starts a preview session.

* **Next.js:**

  ```tsx filename=app/layout.tsx
  import { type ReactNode } from "react";
  import { PrismicPreview } from "@prismicio/next";
  import { repositoryName } from "@/prismicio";

  export default function RootLayout({ children }: { children: ReactNode }) {
    return (
      <html lang="en">
        <body>{children}</body>
        <PrismicPreview repositoryName={repositoryName} />
      </html>
    );
  }
  ```

  ```tsx filename=app/api/preview/route.ts
  import { NextRequest } from "next/server";
  import { redirectToPreviewURL } from "@prismicio/next";
  import { createClient } from "@/prismicio";

  export async function GET(request: NextRequest) {
    const client = createClient();

    return await redirectToPreviewURL({ client, request });
  }
  ```

  ```tsx filename=app/api/exit-preview/route.ts
  import { exitPreview } from "@prismicio/next";

  export function GET() {
    return exitPreview();
  }
  ```

  Register the preview route in your repository:

  ```sh
  npx prismic preview add http://localhost:3000/api/preview
  ```

* **Next.js (Pages Router):**

  ```tsx filename=pages/_app.tsx
  import type { AppProps } from "next/app";
  import { PrismicPreview } from "@prismicio/next/pages";
  import { repositoryName } from "@/prismicio";

  export default function App({ Component, pageProps }: AppProps) {
    return (
      <>
        <Component {...pageProps} />
        <PrismicPreview repositoryName={repositoryName} />
      </>
    );
  }
  ```

  ```tsx filename=pages/api/preview.ts
  import type { NextApiRequest, NextApiResponse } from "next";
  import { setPreviewData, redirectToPreviewURL } from "@prismicio/next/pages";
  import { createClient } from "@/prismicio";

  export default async function handler(
    req: NextApiRequest,
    res: NextApiResponse,
  ) {
    const client = createClient({ req });

    setPreviewData({ req, res });

    await redirectToPreviewURL({ req, res, client });
  }
  ```

  ```tsx filename=pages/api/exit-preview.ts
  import type { NextApiRequest, NextApiResponse } from "next";
  import { exitPreview } from "@prismicio/next/pages";

  export default async function handler(
    req: NextApiRequest,
    res: NextApiResponse,
  ) {
    exitPreview({ res, req });
  }
  ```

  Register the preview route in your repository:

  ```sh
  npx prismic preview add http://localhost:3000/api/preview
  ```

* **Nuxt:**

  `@nuxtjs/prismic` adds the toolbar and a `/preview` route. No files are needed.

  Register the preview route in your repository:

  ```sh
  npx prismic preview add http://localhost:3000/preview
  ```

* **SvelteKit:**

  ```svelte filename=src/routes/+layout.svelte
  <script lang="ts">
    import type { Snippet } from "svelte";
    import { PrismicPreview } from "@prismicio/svelte/kit";
    import { repositoryName } from "$lib/prismicio";

    type Props = {
      children: Snippet;
    };

    let { children }: Props = $props();
  </script>

  <main>{@render children()}</main>
  <PrismicPreview {repositoryName} />
  ```

  ```ts filename=src/routes/api/preview/+server.ts
  import { redirectToPreviewURL } from "@prismicio/svelte/kit";
  import { createClient } from "$lib/prismicio";

  export async function GET({ fetch, request, cookies }) {
    const client = createClient({ fetch });

    return await redirectToPreviewURL({ client, request, cookies });
  }
  ```

  Previewed pages are served under `/preview`, for example `/preview/about`. A route matcher recognizes the prefix, all page routes are nested in a `[[preview=preview]]` directory, and `prerender` is set to `auto` so that previewed pages render on demand.

  ```ts filename=src/params/preview.ts
  export function match(param) {
    return param === "preview";
  }
  ```

  ```ts filename=src/routes/+layout.server.ts
  export const prerender = "auto";
  ```

  Register the preview route in your repository:

  ```sh
  npx prismic preview add http://localhost:5173/api/preview
  ```

After you deploy, add another preview with your production domain. You can also manage previews in your repository under **Settings** → **Previews**.

## Content change webhook

How your website learns that content changed in Prismic.

In Next.js with the App Router, the revalidation route clears every cached Prismic request. It uses the `prismic` tag set in the [Prismic client](#prismic-client).

```tsx filename=app/api/revalidate/route.ts
import { NextResponse } from "next/server";
import { revalidateTag } from "next/cache";

export async function POST() {
  revalidateTag("prismic", "max");

  return NextResponse.json({ revalidated: true, now: Date.now() });
}
```

Create a webhook that calls the route when content is published or unpublished:

```sh
npx prismic webhook create https://example.com/api/revalidate \
  --trigger documentsPublished \
  --trigger documentsUnpublished
```

In the Pages Router, Nuxt, and SvelteKit, pages are built statically. Add a webhook that rebuilds your website when content changes. See [Add a webhook to your hosting provider](https://prismic.io/docs/webhooks.md#add-a-webhook-to-your-hosting-provider).

## Generated TypeScript types

Slice Machine writes [TypeScript](https://www.typescriptlang.org/) types for your content models to `prismicio-types.d.ts`. The Prismic client, [`@prismicio/client`](https://prismic.io/docs/technical-reference/prismicio-client.md), uses them.

```ts
import { createClient, type Content } from "@prismicio/client";

const client = createClient("example-prismic-repo");
const blogPost = await client.getByUID("blog_post", "my-first-post");
//    ^ Typed as BlogPostDocument

// Every model is also available through the `Content` type.
Content.BlogPostDocument;
Content.CallToActionSlice;
```

Do not edit the file. Slice Machine rewrites it on every model change. Change its location with the `generatedTypesFilePath` [adapter option](#slicemachineconfigjson).

## Slice libraries

A slice library is a directory of slices. The default library is `src/slices` in Next.js, `slices` in Nuxt, and `src/lib/slices` in SvelteKit.

Slice Machine generates an `index.ts` in each library that exports its components for `<SliceZone>`. Do not edit the file.

Use more than one library to organize your code. Content writers still see all slices in one list. To add a library, add its directory to `libraries` in `slicemachine.config.json`, then restart Slice Machine.

```json filename=slicemachine.config.json {4-7}
// prettier-ignore
{
  "repositoryName": "example-prismic-repo",
  "adapter": "@slicemachine/adapter-next",
  "libraries": [
    "./src/slices/marketing",
    "./src/slices/blog"
  ],
  "localSliceSimulatorURL": "http://localhost:3000/slice-simulator"
}
```

## Model files

Slice Machine stores each content model as JSON in your project:

* **Slices**: `model.json` in the slice's directory in its [slice library](#slice-libraries), for example `src/slices/CallToAction/model.json`.
* **Page types and custom types**: `customtypes/<id>/index.json`.

Slice Machine edits these files for you. Two options are not in the Slice Machine UI and must be added in the JSON:

* **Integration fields**: Add a field with the type `IntegrationFields` and a `catalog` option. See the [integration field](https://prismic.io/docs/fields/integration.md#add-an-integration-field-to-a-content-model) guide for the JSON.
* **Rich text labels**: Add a `labels` array to the rich text field's `config`. See the [rich text](https://prismic.io/docs/fields/rich-text.md#use-labels-for-custom-formatting) guide for the JSON.

# Prismic CLI in a Slice Machine project

The [Prismic CLI](https://prismic.io/docs/cli.md) reads the repository name from `slicemachine.config.json`. The command groups that manage the repository work in a Slice Machine project without extra options:

* `preview`: Preview URLs and the slice simulator URL.
* `token`: Access tokens.
* `webhook`: Webhooks.
* `locale`: Locales.
* `repo`: Repository name and API access.
* `login`, `logout`, `whoami`, and `docs`.

Run `npx prismic <command> --help` to list the subcommands of a group.

Do not use the model commands: `type`, `slice`, `field`, `push`, `pull`, `sync`, `status`, and `gen`. They expect a Type Builder project with `prismic.config.json`. Model content in Slice Machine instead.

`npx prismic init` [migrates the project to the Type Builder](#migrate-to-the-type-builder).

# Environments

[Environments](https://prismic.io/docs/environments.md) let you change content models without affecting production content. Slice Machine pushes models to an environment and points your website at it.

> Environments are a Platinum and Enterprise plan feature. [Learn more](https://prismic.io/docs/environments.md).

## Select an environment

Select the active environment with the dropdown in the top-left corner. Pushes go to the selected environment.

Slice Machine writes the selected environment to an environment variable in `.env.local`:

* **Next.js**: `NEXT_PUBLIC_PRISMIC_ENVIRONMENT`
* **Nuxt**: `NUXT_PUBLIC_PRISMIC_ENVIRONMENT`
* **SvelteKit**: `VITE_PRISMIC_ENVIRONMENT`

Slice Machine deletes the variable when you select the production repository.

## Fetch content from an environment

Read the environment variable in your [Prismic client](#prismic-client). Your production website keeps using the production repository.

* **Next.js:**

  Update `prismicio.ts` to use `NEXT_PUBLIC_PRISMIC_ENVIRONMENT`:

  ```ts filename=prismicio.ts
  export const repositoryName = // [!code ++]
    process.env.NEXT_PUBLIC_PRISMIC_ENVIRONMENT || sm.repositoryName; // [!code ++]
  ```

* **Nuxt:**

  **No code changes are necessary**. `@nuxtjs/prismic` reads the variable automatically.

* **SvelteKit:**

  Update `prismicio.ts` to use `VITE_PRISMIC_ENVIRONMENT`:

  ```ts filename=prismicio.ts
  export const repositoryName = // [!code ++]
    import.meta.env.VITE_PRISMIC_ENVIRONMENT || sm.repositoryName; // [!code ++]
  ```

## Push changes to production

When your model changes are tested in an environment, push them to production.

1. **Select the production environment**

   Select the production repository with the dropdown in the top-left corner.

2. **Push to Prismic**

   [Push your changes](#push-changes-to-prismic). Your model changes are listed on the **Review changes** page.

# Troubleshooting

## Chrome blocks local network access

If an "Oops" screen appears when you log in from Slice Machine, Chrome can be blocking local network access.

Starting in Chrome 142, [local network access restrictions](https://developer.chrome.com/blog/local-network-access) stop public websites from accessing private network resources without permission.

To fix this:

1. When Chrome asks for permission to access your local network, click **Allow**.
2. If Chrome does not ask, go to **Settings > Privacy and security > Site settings** and give `prismic.io` **Local network access**.

## The simulator cannot render slices

If slice previews time out or show a "Slice Machine can't render your slice" error, your website can be blocking iframes. Slice Machine and the [Page Builder live preview](https://prismic.io/docs/previews.md) load the [slice simulator page](#slice-simulator-page) in an iframe. Security headers that stop embedding block the simulator, even if the page works when you open it directly.

Common blockers are:

* `X-Frame-Options: SAMEORIGIN` or `DENY`
* `Content-Security-Policy` directives such as `frame-ancestors 'none'` or `frame-ancestors 'self'`

To fix this, exclude `/slice-simulator` from your security header rules and keep them on all other pages. The rules can be in your framework configuration, middleware, a reverse proxy, or your hosting platform.

## Slice preview fails on Vercel with password protection

If the simulator works on localhost but fails on a Vercel deployment with **Deployment Protection**, Vercel is blocking the simulator's assets. See the [Slices guide](https://prismic.io/docs/slices.md#slice-preview-fails-on-vercel-with-password-protection).
