Keplux logo.

Creating a starter project with Next.js, TypeScript, Sanity Studio v3, and ChakraUI

Learn how to create a starter project that uses Next.js, TypeScript, Sanity Studio v3, and Chakra-UI. Feel free to replace Chakra-UI with any other component library, or remove it completely!

By Chris Jardine

December 7, 2022

A person programming in the dark.

Learn how to create a starter project with Next.js, TypeScript, Sanity Studio v3, and Chakra-UI. This guide assumes you already know how to use Next.js.

Feel free to use any other component library or technology, if any, for your front end. Chakra-UI is great, but other options include Material Design, Mantine, AntD, and PrimeReact. If you want something less opinionated and prefer styling with class names over props, TailwindCSS mixed with Headless UI is awesome, too.

Next.js

To start, create a new Next.js project:

npx create-next-app@latest

Give the project a name, such as next-sanity-chakra-starter.

The next two prompts ask if you want to use TypeScript and ESLint. Select yes for both prompts.

Once complete, open the project in VS Code:

cd next-sanity-chakra-starter
code .

Optional: If you're adding TypeScript to an existing project

If you're following this guide with an existing project, create a file called tsconfig.json at the root of your project. When you run npm run dev, installation instructions will be shown to set up TypeScript. Once done, change your .js files to .ts and your .jsx files to .tsx.

Note: depending on your setup, you may not be able to convert some config files. That's fine, just leave them as they were.

Optional: Configure ESLint, TypeScript ESLint, and Prettier

This is optional, but I highly recommend that you don't skip this step. You'll be glad to have them set up. I have a separate article outlining how to do this, which you can find here.

Cleanup

When I start a new project, the first thing I like to do is remove the unnecessary boilerplate provided by Next.js. Fortunately, there's a lot less than there used to be.

  1. Delete everything from pages/index.tsx, leaving only an empty div. Personally, I prefer using arrow functions, so I delete everything and create a new arrow function.
  2. If you're using Chakra-UI or some other component library, you won't need CSS modules. You can delete styles/Home.module.css.
  3. Repeat step 1 with pages/_app.tsx.

Depending on the version of Next.js you're using, you may also have unneeded assets in the public directory that can be deleted.

Results

If you followed along, the files we changed now look like this:

const Home = () => {
  return <div></div>;
};

export default Home;

Sanity Studio v3

The great thing about Sanity Studio v3 is that we can embed the Studio directly in our Next.js project rather than running it on a separate server. Unfortunately, I've not come across a way to create Sanity projects without having it output a project, so we have to do that and then delete the project. Make sure to follow along though, as there are a couple files we're going to take from the output project first just to make our lives a little easier.

Create a new Sanity project

Since Sanity Studio v3 isn't officially released, we need to install it with the @dev-preview tag:

npm create sanity@dev-preview

Follow the steps:

  1. Login type: Log in using whichever provider you used to create your Sanity account. If you don't have one, create one first here.
  2. Select project to use: We want to create a new project. I named mine keplux-blog since I'm going to be building off this starter to create this blog :)
  3. Use the default dataset configuration: yes
  4. Project output path: Just use the preset output path because we'll be deleting it anyway.
  5. Select project template: Clean project with no predefined schemas
  6. Do you want to use TypeScript? Yes
  7. Package manager to use for installing dependencies: npm

You'll now have a new directory in your project with the name of whatever you chose for the name is step 4.

Fix the project structure

Create a src directory at the root of your project and another directory inside it called studio. From the generated project, move the schemas and static directories into your new src/studio directory. Move the sanity.cli.ts and sanity.config.ts files at the root of your project there as well.

Now you can delete the rest of the generated Sanity folder. Your project should now contain the following structure:

...
+- src
| +- studio
| +- schemas
| +- index.ts
| +- static
| +- .gitkeep
| +- sanity.cli.ts
| +- sanity.config.ts
...

Install required dependencies

If you checked out the package.json file in the project we deleted, you probably noticed that it included some dependencies that we don't have. We need them, so install them now:

npm i sanity@dev-preview next-sanity @sanity/image-url @portabletext/react react-is styled-components
npm i -D @sanity/eslint-config-studio

Next, add @sanity/eslint-config-studio to the extends property of your ESLint configuration file.

Finally, open sanity.config.ts and add basePath: '/studio' in the configuration object. This is the route we use to access the Studio in the browser. Feel free to adjust it if you want.

Create a Sanity client

To be able to query Sanity, we need to have a client configured with our project details. We'll use the next-sanity package for this, which includes a createClient function.

Create a new file: src/studio/client.ts. I like to keep everything Sanity related here, but feel free to move things around in a way that fits your structure.

Add the following to the file:

src/studio/client.ts
import { createClient } from 'next-sanity';
import config from '../../../sanity.config';

export const client = createClient({
  ...config,
  useCdn: true,
  apiVersion: '2022-03-13',
});

ts

The createClient function takes in an object of type ClientConfig. We spread our previously created configuration file in the object and add the useCdn and apiVersion properties.

useCdn is an optional, but recommended, option that will allow Sanity to respond with cached data, which results in faster performance . You can read more about it here.

apiVersion is optional, but highly recommended and will result in a warning if it's not set. Simply put, set it to the date that you start your project. Your project will use the API in its state from that date, so future updates to the API won't mess up your project.

The client can now be used to make requests!

Create a route for the Studio

This part makes use of dynamic routing in Next.js. Since the basePath was previously define as /studio, we need to create a new directory in the pages directory called studio.

Ultimately, the Studio will generate many routes and it's impossible to hardcode them. Next.js makes this super easy to handle. All we need to do is create a single file inside the pages/studio directory called [[...index]].tsx. This weird filename is known as an optional catch-all route. The optional part ensures that the base route at /studio is handled in addition to /studio/some/random/sub-route and any other route the Studio comes up with.

In the route file, add the following code:

pages/studio/[[...index]].tsx
import { NextStudio } from 'next-sanity/studio';
import sanityConfig from '../../sanity.config';

const StudioPage = () => {
  return <NextStudio config={sanityConfig} />;
};

export default StudioPage;

tsx

Test it out

We can now access the Studio at http://localhost:3000/studio. Go ahead and run your project:

npm run dev

If you see an error about @sanity/ui, delete your node_modules directory and package-lock.json file. Then reinstall your dependencies with npm i.

CorsOriginError

If you get here, great! Chances are, you've seen several variations of CORS-related errors in the past. They can be annoying and frustrating to fix, but this one is easy!

When you create a new Sanity project, Sanity automatically creates a CORS origin host at http://localhost:3333. If you've used Sanity before, you know that's where you'd normally access your Studio. In our case, we're no longer running a separate server because the Studio is built right into our project. So, unless you've changed it, you Next.js project should be running on port 3000.

So, how do you fix it?

All you have to do is go to your project's API settings at https://www.sanity.io. Under CORS origins, you can delete http://localhost:3333. Then, click Add CORS origin and enter http://localhost:3000 (or whatever port your Next.js server is running on). Check the box next to Allow credentials and press Save.

Now the Studio is working! You should see a note with the title No document types. Perfect!

Sanity Studio Vision Plugin

Sanity has a lot of plugins, and you can even create some of your own. That's beyond the scope of this guide, but there's one plugin we want installed on our starter project.

To be able to query our data from within the Studio, we need to add the Studio Vision plugin:

npm i --save-exact @sanity/vision@dev-preview

The @dev-preview tag here will install the v3-ready version of the plugin.

To enable it, open sanity.config.ts and add the Vision Tool to the plugins array:

sanity.config.ts
import { visionTool } from '@sanity/vision';
// ... other imports

const config = defineConfig({
  // ... other properties
  plugins: [
    // ... other plugins
    visionTool({
      defaultApiVersion: 'v2021-10-21',
      defaultDataset: 'production'
    })
  ]
})

ts

The defaultApiVersion and defaultDataset properties are optional, but make sure the values match your setup if you use them.

Now, when you go to your Studio, you should see a button labeled Vision next to the Desk button.

Final Notes

At this point, the starter can be pushed to GitHub and be cloned. To clean things up a bit, go to the sanity.cli.ts and sanity.config.ts files and set the projectId and dataset properties to empty strings. These will need to match the Sanity project being worked on, so there's no sense in leaving your project's settings in the public repo. Don't worry if you accidentally commit your projectId and dataset, though, as they're considered publicly accessible anyway.

To use the starter, I would use the following process:

  1. Clone the repo.
  2. Install dependencies with npm i.
  3. Create a new Sanity project with npx create sanity@dev-preview.
  4. Delete the generated project.
  5. Update the CORS origins on the Sanity website and copy the projectId from the interface. You should already know the dataset name, but you can also find that on the website. Enter those values into sanity.cli.ts and sanity.config.ts.

Chakra-UI

This part is easy, but I like to include it in my starter so I don't have to do it every time.

Install required dependencies

npm i @chakra-ui/react @emotion/react @emotion/styles framer-motion

Wrap the App with ChakraProvider

Go into /pages/_app.tsx and wrap your app with the ChakraProvider component:

/pages/_app.tsx
import { ChakraProvider } from '@chakra-ui/react';
import type { AppProps } from 'next/app';
import '../styles/globals.css';

const App = ({ Component, pageProps }: AppProps) => {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  );
};

export default App;

tsx

Latest posts

Content modeling with Sanity schemas

January 25, 2023