The fastest way to get started with Makeswift on a new Next.js project is to follow the quickstart guide. If you have an existing Next.js application or want to set things up yourself, continue with the rest of this guide.

System requirements

  • Node.js 18.17 or a later version.
  • macOS, Windows (including WSL), and Linux are supported.

Geting started

1

Open your Next.js project

First, open your Next.js project. If you don’t already have one, head over to the Next.js documentation to get one set up. If you do have one, please verify you are using Next.js 13.4 or a later version that is using App Router.

If you are not using App Router, here’s how to incrementally adopt it.

2

Install dependencies

Install the @makeswift/runtime package. This package contains all of the necessary code to integrate Makeswift into your Next.js app.

npm install @makeswift/runtime
3

Add API key to environment variables

Requesting data through the Makeswift client requires a site API key from Makeswift. In the Makeswift builder, go to Settings > Host and copy the API key for the site.

Once the API key is in your clipboard, open your .env.local file and paste the snippet below.

MAKESWIFT_SITE_API_KEY=paste-your-api-key-here
4

Add Makeswift runtime and client

Create files for the Makeswift runtime and client in a src/makeswift directory.

This guide assumes you are using a src directory. If you aren’t, make sure to update your paths to remove src. For example, src/makeswift would become makeswift

5

Add the Makeswift API handler

Similar to NextAuth.js, Makeswift uses an API handler to communicate with your Next.js app. Create the file src/app/api/makeswift/[...makeswift]/route.ts.

It is important this file has that exact name and path. The extension can be .js or .ts.

src/app/api/makeswift/[...makeswift]/route.ts
import { MakeswiftApiHandler } from "@makeswift/runtime/next/server";
import { strict } from "assert";

import { runtime } from "@/makeswift/runtime";

strict(
  process.env.MAKESWIFT_SITE_API_KEY,
  "MAKESWIFT_SITE_API_KEY is required"
);

const handler = MakeswiftApiHandler(process.env.MAKESWIFT_SITE_API_KEY, {
  runtime,
});

export { handler as GET, handler as POST };

This API route adds support for Draft Mode, on-demand revalidation, and other features that make Makeswift work seamlessly with your Next.js app.

6

Add the Next.js plugin

Next.js plugins are configured in the project’s next.config.js file by wrapping nextConfig. The Makeswift Next.js plugin whitelists Makeswift image domains and sets up rewrites to enable draft mode in the Makeswift builder.

7

Register components with Makeswift

Create a file for registered components called src/makeswift/components.tsx. In this example, only one component is registered. However, as you register more components, we recommend creating separate files for each component and rolling up the imports in the src/makeswift/components.tsx file. Learn more about registering components.

src/makeswift/components.tsx
import { runtime } from "@/makeswift/runtime";
import { Style } from "@makeswift/runtime/controls";

function HelloWorld(props) {
  return <p {...props}>Hello, world!</p>;
}

runtime.registerComponent(HelloWorld, {
  type: "hello-world",
  label: "Hello, world!",
  props: {
    className: Style(),
  },
});
8

Create Makeswift provider component

Create a client component for the Makeswift providers.

src/makeswift/provider.tsx
"use client";

import { runtime } from "@/makeswift/runtime";
import {
  ReactRuntimeProvider,
  RootStyleRegistry,
} from "@makeswift/runtime/next";
import "@/makeswift/components";

export function MakeswiftProvider({ children }: { children: React.ReactNode }) {
  return (
    <ReactRuntimeProvider runtime={runtime}>
      <RootStyleRegistry>{children}</RootStyleRegistry>
    </ReactRuntimeProvider>
  );
}
Make sure to import your src/makeswift/components.tsx file here to ensure your registered components are available in the builder.
9

Update the root layout

In your root layout, wrap your app with the MakeswiftProvider component created in the last step, import the registered components, and add the DraftModeScript to the head. This script enables Draft Mode when inside the Makeswift builder.

src/app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { MakeswiftProvider } from "@/makeswift/provider";
import { DraftModeScript } from "@makeswift/runtime/next/server";
import "@/makeswift/components";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <head>
        <DraftModeScript />
      </head>
      <body className={inter.className}>
        <MakeswiftProvider>{children}</MakeswiftProvider>
      </body>
    </html>
  );
}
10

Add a route for Makeswift pages

Create an optional catch-all route named [[...path]]. This catch-all route will fetch page data from Makeswift and pass it to be rendered in the Page component.

src/app/[[...path]]/page.tsx
import { getSiteVersion } from "@makeswift/runtime/next/server";
import { notFound } from "next/navigation";
import { Page as MakeswiftPage } from "@makeswift/runtime/next";

import { client } from "@/makeswift/client";

type ParsedUrlQuery = { path?: string[] };

export async function generateStaticParams() {
  const pages = await client.getPages().toArray();

  return pages.map((page) => ({
    path: page.path.split("/").filter((segment) => segment !== ""),
  }));
}

export default async function Page({ params }: { params: ParsedUrlQuery }) {
  const path = "/" + (params?.path ?? []).join("/");
  const snapshot = await client.getPageSnapshot(path, {
    siteVersion: getSiteVersion(),
  });

  if (snapshot == null) return notFound();

  return <MakeswiftPage snapshot={snapshot} />;
}

Delete the root page component src/app/page.tsx file to ensure that all pages (including the home page) are managed by Makeswift.

Optional catch-all routes match the parent route which, in this case, would be the root page /. If you wanted to have a hard-coded home page (not managed by Makeswift), you could use a (non-optional) catch-all route which does not match the parent route and uses single brackets instead (ex. [...path]).

11

Start the local dev server

Run the local development script. This will start the Next.js app at http://localhost:3000.

npm run dev

If port 3000 is already in use, Next.js will try port 3001, then 3002, and so forth until it finds an unused port.

Take note of this port for the next step.
12

Add your app's URL to Makeswift

Finally, open the Makeswift builder, navigate to Settings > Host, and add your app’s URL. If you haven’t changed anything in the example and the server is running on port 3000, the app’s URL should be http://localhost:3000.

When you’re ready to deploy, set up a separate site and use your deployment URL instead of http://localhost:3000. You can keep this site for local development.

13

Start building

Great job! You should be able to create a page in Makeswift and start dropping in registered components from the left toolbar.