Managing a Remix Site's Content With Sanity.io
Tags: typescript, sanity, remix, vercel
Published: 2022-08-23 21:43:23

---
title: Managing a Remix Site's Content With Sanity.io
published: true
date: 2022-08-23 20:56:15 UTC
tags: typescript,sanity,remix,vercel
canonical_url: https://sabinadams.hashnode.dev/managing-a-remix-sites-content-with-sanityio
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1aqy2jpjf34ucbvlspk.png
---

In this day and age, the world runs on data. Your phone, your favorite game, the internet itself! Everything comes down to data. This has lead to a realization by developers over the years: _data is hard to manage_.

# Introduction

In this article, you will learn how to use [Sanity.io](https://www.sanity.io/), a content platform that includes the [Content Lake](https://www.sanity.io/docs/datastore) where your content is stored, a content management studio and various APIs to access your content from. Sanity will be used to manage the content _(data)_ of a book catalog's website built with [Remix](remix.run/).

By the end, you will have Sanity set up to manage your content and a fully functional Remix application. This application will use Sanity's GraphQL API to retrieve your content.

Finally, you will deploy your finished website using Vercel.

# Prerequisites

While not completely necessary, I believe you will get the most out of this article if you come with:

- A basic understanding of JavaScript and its tooling
- Experience working with React
- A basic understanding of GraphQL

Make sure you have [node.js](https://nodejs.org/en/) installed on your machine.

# Tools you will use

Below are the various tools and technologies you will get to touch in this tutorial:

- [Remix](https://remix.run/), your application framework
- [Sanity](https://www.sanity.io/), a headless CMS to manage your data
- [graphql-request](https://github.com/prisma-labs/graphql-request), a minimal GraphQL client
- [GraphQL Codegen](https://www.graphql-code-generator.com/), generates TypeScript types from a GraphQL schema
- [TailwindCSS](https://tailwindcss.com/), as your CSS framework
- [Vercel](https://vercel.com/), as your website hosting provider

# Set up a Sanity.io project

Sanity gives you the ability to set up Sanity Studio, an application that allows you to configure different content types and inputs. The studio interacts with Sanity's APIs, allowing you to manage your data from a self-hosted application.

In order to set up a Sanity project, you first need to install the Sanity CLI:

```
npm i -g @sanity/cli

```

Next, initialize a Sanity project in a directory where you would like the project to live. For the purposes of this tutorial I will work in `/Documents/projects`:

```
# /Documents/projects
sanity init

```

> **Note** : If you did not already have a Sanity account set up, `sanity init` will walk you through setting up a new account.

This will walk you through setting up your project and will download a starter template of Sanity Studio. You will be prompted for a few bits of data and asked a few questions about your project. I chose the name `catalog-sanity` for my project and will use that for the remainder of this tutorial.

At some point in the process, you will be asked to **Select project template**. Select the **Clean project with no predefined schemas** option, as you will configure this project yourself.

Once your project has been set up, follow the instructions outputted to start up Sanity Studio:

```
# /Documents/projects
cd catalog-sanity
sanity start

```

Sanity Studio should start up at [localhost:3333](http://localhost:3333). Pop that open to see what the starter template looks like:

> **Note** : You will be asked to sign in to the studio. Use the credentials you used when creating an account on Sanity.io.

![Sanity Studio Starter](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946090885/HaVndQHyc.png)

You should see a page similar to the one above. As the message on the page indicates, you have not yet configured a schema.

In the next section, you will set up a schema to define a `Book` document and its `field`s.

## Define a `Book` document type

In Sanity, JavaScript objects are used to build schemas that define your content model. This model consists of "documents", or the types of content you are creating. In this catalog scenario, the only type of content you will create is `Book`s.

Open up your Sanity project in a code editor. You will find a folder within named `schemas`. This is the folder that will contain all of your project's schemas.

Create a new file within the `schemas` folder named `book.js`:

```
# /Documents/projects/catalog-sanity
touch schemas/book.js

```

Add the following code to the new `book.js` file:

```
// /Documents/projects/catalog-sanity/schemas/book.js

export const book = {
  name: 'book',
  type: 'document',
  title: 'Book',
  fields: []
}

```

This object defines a `document` named `book`. Within Sanity Studio, this document will be referred to as `Book` because of the `title` field. The `fields` array is empty at the moment.

In your application, a book will have three pieces of data associated with it:

- `Title`: The title of the book
- `Author`: The author of the book
- `Description`: A quick description of the book

Update the `fields` array to define these data points:

```
// /Documents/projects/catalog-sanity/schemas/book.js

// ...
fields: [
    {
        name: "title",
        type: "string",
        title: "Title",
    }, {
        name: "author",
        type: "string",
        title: "Author",
    }, {
        name: "description",
        type: "text",
        title: "Description",
    },
],
// ...

```

## Apply `Book` to your schema

At this point, you have completely defined the `Book` document type, however that type has not yet been applied to the project's schema.

In `schemas/schema.js`, import the new `Book` type and add it to the `types` array within the `createSchema` configuration object argument:

```
// /Documents/projects/catalog-sanity/schemas/schema.js

import createSchema from "part:@sanity/base/schema-creator";

import schemaTypes from "all:part:@sanity/base/schema-type";
import { book } from "./book"; // <- Import the type

export default createSchema({
  name: "default",
  types: schemaTypes.concat([
    book // <- Add it to the array
  ]),
});

```

Once you save all of your changes and head back to the browser, you should now see the UI updated with your new content type.

![Sanity Studio With Book](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946665217/SNLL-eTId.png)

Clicking the **Book** option under the **Content** header will reveal a list of your existing books _(it will be empty for now)_. Here, you are provided all of the tools you need to create, update, and delete books.

![Sanity Studio Book View](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946705371/D-VNnOcG0.png)

Create a couple of books by clicking the pencil icon on the top right of that section:

![Sanity New Book Icon](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946771328/XB3ATO0uw.png)

Once you've added a few books, you are almost ready to move on to the last section!

The last thing you need to do, however, is install the `@sanity/cli` as a development dependency in the project:

```
npm i -D @sanity/cli

```

This will allow you to deploy to Vercel later on in this tutorial.

# Build the Remix application

Now that Sanity is set up to manage your content, you need a way to display that content. You will use [Remix](https://remix.run/), a full stack JavaScript framework, to create a book catalog website where your data will be displayed.

## Initialize a Remix application

This application will be separate from the Sanity project. Navigate out of the Sanity project's directory and into a directory where you would like your Remix project to live. Then run the following command:

```
# /Documents/projects
npx create-remix@latest

```

This command will ask you a series of questions and scaffold the beginnings of a Remix application for you. Answer the questions with the following:

- **Where would you like to create your app?** : `catalog-remix`
- **What type of app do you want to create?** : `Just the basics`
- **Where do you want to deploy?** : `Vercel`
- **TypeScript or JavaScript?** : `TypeScript`
- **Do you want me to run `npm install`?** : `Yes`

The options above will set up a Remix starter template in a folder named `catalog-remix`. This application will be a bare bones template configured to use TypeScript and deploy to Vercel.

Enter the new directory and run the `dev` script to start up the development server:

```
# /Documents/projects
cd catalog-remix && npm run dev

```

Now, if you open up a web browser and navigate to [localhost:3000](http://localhost:3000), you should see the starter page Remix provided!

![CleanShot 2022-08-19 at 14.44.10.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660945466251/SESUVuUEf.png)

## Set up TailwindCSS

This starter is very basic and is not very visually appealing yet. To style your application, you will use [TailwindCSS](https://tailwindcss.com/).

To set up TailwindCSS, you first need to install a few dependencies:

```
# /Documents/projects/catalog-remix
npm i -D tailwindcss postcss autoprefixer concurrently

```

These packages provide you the TailwindCSS CLI and PostCSS. You also installed `autoprefixer`, which is a PostCSS plugin needed to use TailwindCSS. `concurrently` is a tool that will allow you to run your development server and build your TailwindCSS styles at the same time.

With all of those pieces installed, run the following command to use TailwindCSS CLI to initialize TailwindCSS in your project:

```
# /Documents/projects/catalog-remix
npx tailwindcss init

```

This command will generate a new file at the root of your project named `tailwind.config.js`. This file is where you will configure TailwindCSS.

Open that file and add the following value to the `content` key's array:

```
// /Documents/projects/catalog-remix/tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}", // <-- Added this "blob"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

```

What this does is tells TailwindCSS which files in your project will be using its utilities and classes. This helps TailwindCSS decide which of its utilities and classes should be generated into its minified output when a build is run on your project.

The next step is to update your development scripts to include a step to build your CSS when you build or develop your application.

Open up `package.json` and replace the contents in the `scripts` section with the following:

```
// /Documents/projects/catalog-remix/package.json 

// ...
"scripts": {
  "build": "npm run build:css && remix build",
  "build:css": "tailwindcss -m -i ./styles/app.css -o app/styles/app.css",
  "dev": "concurrently \"npm run dev:css\" \"remix dev\"",
  "dev:css": "tailwindcss -w -i ./styles/app.css -o app/styles/app.css"
},
// ...

```

Now when you run `npm run dev` or `npm run build`, rather than simple starting up or building your Remix application it will also generate a CSS file based off of the TailwindCSS classes and utilities you are using in your application.

These steps require the existence of TailwindCSS's base "layers", as signified in the `-i ./styles/app.css` argument of the `tailwindcss` command. Those layers provide the pieces TailwindCSS uses to provide its styling.

Create a new directory named `styles` and within that directory create a new file named `app.css`:

```
# /Documents/projects/catalog-remix
mkdir styles && touch styles/app.css

```

Add the following CSS to that file to import TailwindCSS's layers:

```
/* /Documents/projects/catalog-remix/styles/app.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

```

The new steps that build your CSS file will output your CSS into a file at `app/styles/app.css`. In order to actually use those generated styles, however, you will need to import that file into your application.

In `app/root.tsx`, add the following to import those styles and use them in your application:

```
// /Documents/projects/catalog-remix/app/root.tsx

import type { 
  MetaFunction,
  LinksFunction // <-- Added the LinksFunction type
} from "@remix-run/node";

// ... other imports

import styles from "./styles/app.css"

export const links: LinksFunction = () => {
  return [{ rel: "stylesheet", href: styles }]
}

// ...

```

Now TailwindCSS is configured and ready to use in your application!

To verify everything is working correctly, replace the contents of `app/routes/index.tsx` with the following code:

```
// /Documents/projects/catalog-remix/app/routes/index.tsx

export default function Index() {
  return (
    <div className="h-screen w-full p-4 font-mono">
      <div className="rounded-xl p-6 bg-gray-100 border-4 border-gray-600">
        <h2 className="font-bold text-4xl text-gray-600">Book Catalog</h2>
      </div>
    </div>
  );
}

```

If you run `npm run dev` and head back to [localhost:3000](http://localhost:3000), you should see a page similar to the following:

![TailwindCSS Working](https://cdn.hashnode.com/res/hashnode/image/upload/v1660960841647/HOGkVVG8X.png)

If you get a page similar to this one, TailwindCSS is set up and working!

## Build a `Book` component

Now, you need a component that will display each book in your catalog.

Create a new folder in the `app` directory named `components`. Then create a file within that folder named `Book.tsx`:

```
# /Documents/projects/catalog-remix
mkdir app/components
touch app/components/Book.tsx

```

Paste the following function into that file:

```
// /Documents/projects/catalog-remix/app/components/Book.tsx

export default function Book() {
    return (
        <a href="/" className="m-2 rounded-xl p-6 border-4 border-gray-600 transition hover:-translate-y-1">
            <h2 className="font-bold text-2xl text-gray-600">How To: DevRel</h2>
            <p className="text-xs text-gray-400">by Sabin Adams</p>
            <p className="text-gray-500 mt-2 text-md">
                This book walks the reader through the ins and outs of working in the DevRel space.
            </p>
        </a>
    );
}

```

This function simply returns some JSX, which will render a dummy `Book` onto the page. The data in this component is static for now, however in the next section you will populate this component with your book data from the Sanity API.

Over in `app/routes/index.tsx`, import that new component and render it within a grid a couple of times to populate your screen with a set of dummy books:

```
// /Documents/projects/catalog-remix/app/routes/index.tsx

import Book from '../components/Book' // <-- Imported the `Book` component

export default function Index() {
  return (
    <div className="h-screen w-full p-4 font-mono">
      <div className="rounded-xl p-6 bg-gray-100 border-4 border-gray-600">
        <h2 className="font-bold text-4xl text-gray-600">Book Catalog</h2>
      </div>
      {/* Renders 6 Books within a grid 👇🏻 */}
      <div className="grid grid-cols-3 p-12">
        <Book /><Book /><Book /><Book /><Book /><Book />
      </div>
    </div>
  );
}

```

Back over in your browser, you should now see your set of books rendered in a stylized grid:

![Catalog with dummy data](https://cdn.hashnode.com/res/hashnode/image/upload/v1660964866541/h8-QkmBGq.png)

# Get your data from Sanity.io

At this point you have Sanity set up to manage your content, and a Remix application ready to render some live data.

You will now use Sanity's [GraphQL API](https://www.sanity.io/docs/graphql) to fetch your content and render it into the browser.

To do this, you will make use of a tool called [GraphQL Codegen](https://www.graphql-code-generator.com/) to generate TypeScript types based on the GraphQL schema Sanity provides. You will then use [`graphql-request`](https://github.com/prisma-labs/graphql-request) to actually fetch the data.

![Sanity + Remix.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661201625527/VJ2ogA4ba.png)

## Set up GraphQL Codegen

First, you will set up GraphQL Codegen to generate TypeScript types based off of your GraphQL schema. It will also generate types based on the queries you write that represent the data you actually query for.

To get started, install these packages in your Remix application:

```
# /Documents/projects/catalog-remix
npm i -D graphql @graphql-codegen/cli @graphql-codegen/typed-document-node @graphql-codegen/typescript @graphql-codegen/typescript-operations

```

These give you access to the GraphQL Codegen CLI and all of the plugins you need to generate the types representing your GraphQL schema and queries. In order to generate these types, you first need to configure GraphQL Codegen.

Create a new file at the root of your Remix project named `codegen.yml` with the following contents:

```
# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: <placeholder>
    documents: <placeholder>
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

```

This configuration lets GraphQL Codegen know to generate a file at `app/models/sanity-generated.ts` with all of the types you need.

There are three different configurations provided for this generated file:

- **schema** : The URL of your GraphQL API
- **documents** : Tells the CLI which files in your project have GraphQL queries
- **plugins** : Lets the CLI know which plugins to use to generate types

Currently, the `schema` and `documents` fields have dummy data in them. You will need to populate these.

To populate `schema`, you first need to deploy your Sanity project's GraphQL API. To do so, navigate to the Sanity project's folder and run the following command:

```
# /Documents/projects/catalog-sanity
sanity graphql deploy

```

After running this command, the URL to your GraphQL API will be outputted into the terminal. Copy that URL:

![Sanity GraphQL](https://cdn.hashnode.com/res/hashnode/image/upload/v1660969677694/kdcEMKJMT.png)

Then, paste that value into the `codegen.yml` file's `schema` field:

```
# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: # paste the API URL here #
    documents: <placeholder>
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

```

The next piece you will need to fill in is the `documents` key. You will write all of your queries in a file at `app/graphql`. Create that directory and add a file named `books.query.gql`:

```
# /Documents/projects/catalog-remix
mkdir app/graphql
touch app/graphql/books.query.gql

```

Then paste the file path `./app/graphql/**/*.ts` into the `documents` field in the `codegen.yml` file:

```
# /Documents/projects/catalog-remix/codegen.yml

generates:
  ./app/models/sanity-generated.ts:
    schema: <hidden>
    documents: # paste the file path here #
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

```

GraphQL Codegen is now configured to ready all queries from `.ts` files within the `app/graphql` folder, but you need a way to actually generate the types.

In `package.json`, add the following script to the `scripts` field:

```
// /Documents/projects/catalog-remix/package.json

// ...
"scripts": {
  // ...
  "codegen": "npx graphql-codegen"
}
// ...

```

At this point, you are ready to generate types based off of your queries and the GraphQL Schema! There is only one problem... you don't have any queries yet!

You will use [`graphql-request`](https://github.com/prisma-labs/graphql-request) and its helpers to write your GraphQL queries and fetch the data from Sanity's GraphQL API.

Install the `graphql-request` library:

```
# /Documents/projects/catalog-remix
npm i graphql-request

```

Then, in `app/graphql/books.query.ts`, add the following GraphQL query to fetch your book data:

```
// /Documents/projects/catalog-remix/app/graphql/books.query.ts

import { gql } from "graphql-request";

export default gql`
  query GetBooks {
    allBook {
      _id
      title
      author
      description
    }
  }
`;

```

> **Note** : If you'd like to see all of the data available from the GraphQL API, check out the GraphQL playground by going to your GraphQL API's URL in your web browser.

Now that you have a query written, run the following command to generate your types:

```
# /Documents/projects/catalog-remix
npm run codegen

```

You should see a new `app/models` directory with a file named `sanity-generated.ts` inside of it. This file contains your TypeScript types!

## Query Sanity's GraphQL API

You now have TypeScript types to represent the data you expect to retrieve from the Sanity API. At this point, you can write the queries for your data.

Create a new directory named `services` within the `app` directory and create a file within that directory named `sanity.service.ts`:

```
# /Documents/projects/catalog-remix
mkdir app/services
touch app/services/sanity.service.ts

```

This is where you will write the function that will fetch the data.

Add the following code to create a function that fetches the API for your books and properly types the response:

```
// /Documents/projects/catalog-remix/app/services/sanity.service.ts

import { GraphQLClient } from "graphql-request";
import type { GetBooksQuery } from "../models/sanity-generated";
import BookQuery from "../graphql/books.query";

export async function getBooks() {
  const graphcms = new GraphQLClient(process.env.SANITY_API_URL || "");
  const { allBook } = await graphcms.request<GetBooksQuery>(BookQuery);
  return allBook;
}

```

The code above assumes you have an environment variable named `SANITY_API_URL` that contains the URL of the GraphQL API.

Create a file named `.env` at the root of your project:

```
# /Documents/projects/catalog-remix
touch .env

```

Then add the following contents to that file:

```
# /Documents/projects/catalog-remix/.env

SANITY_API_URL=<your_api_url> 
# Example: SANITY_API_URL=https://gsithqzp.api.sanity.io/v1/graphql/production/default

```

Now that your `getBooks` function is ready and your environment has the correct API URL available you are ready to run your query.

Within Remix, you have the ability to create a ["loader"](https://remix.run/docs/en/v1/guides/data-loading) function that, when deployed, is treated as a serverless function and is deployed separately from the client-side code.

In `app/routes/index.ts`, create a loader function that simply fetches your books and returns them.

```
// /Documents/projects/catalog-remix/app/routes/index.ts

import Book from '../components/Book'
import type { LoaderFunction } from '@remix-run/node';
import { getBooks } from '../services/sanity.service'

export const loader: LoaderFunction = async () => {
  const books = await getBooks()
  return { books }
}
// ...

```

Then, import the [`useLoaderData`](https://remix.run/docs/en/v1/api/remix#useloaderdata) hook Remix provides and use it to capture the results of your loader function. Be sure to type the variable using the `useLoaderData` function's generic:

```
// /Documents/projects/catalog-remix/app/routes/index.ts

// ...

export default function Index() {
  const { books } = useLoaderData<{
    books: GetBooksQuery['allBook'][0][]
  }>()

  return (/* JSX */);
}

```

You are now querying your data and accessing that data from your application. The data from your API In the next section, you will fix up your `Book` component so that it will render the actual book data and render one for each book in the API response.

## Render your Book data

Head back over to `app/components/Book.tsx` and import the `GetBooksQuery` type. Use that type to define a `book` prop on the `Book` component:

```
// /Documents/projects/catalog-remix/app/components/Book.tsx

import type { GetBooksQuery } from "../models/sanity-generated";

export default function Book({ book }: { book: GetBooksQuery['allBook'][0] }) {
  // Component code
}

```

The code above sets up a `book` property on the component whose type matches the type of a single book from your API response.

You can now use that property to render your book data into the component. Update the JSX in that component to use the book's data:

```
// /Documents/projects/catalog-remix/app/components/Book.tsx

import type { GetBooksQuery } from "../models/sanity-generated";

export default function Book({ book }: { book: GetBooksQuery['allBook'][0] }) {
    return (
        <a href="/" className="m-2 rounded-xl p-6 border-4 border-gray-600 transition hover:-translate-y-1">
            <h2 className="font-bold text-2xl text-gray-600">{ book.title }</h2>
            <p className="text-xs text-gray-400">{ book.author }</p>
            <p className="text-gray-500 mt-2 text-md">{ book.description }</p>
        </a>
    );
}

```

Finally, head back to `app/routes/index.ts` and render one `Book` component for each book in your `books` variable:

```
// /Documents/projects/catalog-remix/app/routes/index.ts

// ...

export default function Index() {
  const { books } = useLoaderData<{ books: GetBooksQuery['allBook'][0][] }>()

  return (
    <div className="h-screen w-full p-4 font-mono">
      {/* ... */}
      <div className="grid grid-cols-3 p-12">
        {/* Render the books here 👇🏻 */}
        {books.map(book => <Book book={book} key={book._id} />)}
      </div>
    </div>
  );
}

```

Back over in your browser, you should now see a list of your actual data rendered out onto the page!

![Complete application](https://cdn.hashnode.com/res/hashnode/image/upload/v1661196873468/Vs9GYz5Bu.png)

At this point your application is complete! Sanity is managing all of the data for your book catalog, which you are rendering via your Remix application 🎉

This is something to share with the world! In the next section, you will wrap things up by deploying your application.

# Deploy your applications

In order to deploy this application, you will need to host both projects on GitHub. You will also deploy the Sanity project so you can access your Sanity Studio at any time via the web browser.

## Push both projects to GitHub

> **Note** : If you do not have a GitHub account, you can create one for free [here](https://github.com/signup).

To host your Remix applicaiton on GitHub, you first need to create a new GitHub repository that will hold your code. Head over to the GitHub dashboard and hit the **New** button to create a new repository:

![GitHub Dashboard](https://cdn.hashnode.com/res/hashnode/image/upload/v1661197321551/HHaxAvUBN.png)

You will be asked for a few details about the repository. Give the repository a name and hit **Create repository**. You should then be redirected to a page that looks similar to this one:

![New GitHub Repository Page](https://cdn.hashnode.com/res/hashnode/image/upload/v1661197473281/wnBvf0fFB.png)

Grab the SSH URL for the repository by hitting the copy button signified in the image below:

![Copy SSH URL Button](https://cdn.hashnode.com/res/hashnode/image/upload/v1661197646068/G4GYSN3dV.png)

Finally, in your terminal head over to the Remix application and run the following set of commands:

```
# /Documents/projects/catalog-remix
git init
git remote add origin <YOUR SSH URL>
git branch -m main
git add .
git commit -m "Initial Commit"
git push --set-upstream origin main

```

If you head back over to your GitHub repository page and refresh, you should now see your project's contents:

![Remix Application On GitHub](https://cdn.hashnode.com/res/hashnode/image/upload/v1661197873432/5XKV6r5ZJ.png)

Next, within your Sanity project's code base create a new file at the root named `.gitignore`:

```
# /Documents/projects/catalog-sanity
touch .gitignore

```

Add the following to the contents of that file:

```
node_modules

```

This will ensure you do not push the `node_modules` folder to GitHub.

> **Note** : Your Remix application came with this already set up.

Then, repeat all of the steps you followed to push your Remix application to a new GitHub repository on this project.

Once you have finished adding your Sanity project to its own GitHub repository, you will be ready to deploy your application and the Sanity Studio!

## Deploy the Remix application

You will use [Vercel](https://vercel.com) to deploy and host your applications.

> **Note** : You can create a free account if you do not already have one [here](https://vercel.com/signup).

Once you are in the dashboard, hit the **Add New...** button to create a new project in Vercel:

![Vercel New](https://cdn.hashnode.com/res/hashnode/image/upload/v1661198626370/pyoQAOEbS.png)

Select the **Project** option that drops down when you hit that button:

![Vercel New Project Option](https://cdn.hashnode.com/res/hashnode/image/upload/v1661198750056/o15oFnsOd.png)

You will land on a page where you can choose a GitHub repository to deploy.

> **Note** : You may have to connect your GitHub account. The steps to accomplish this will be on the page if you haven't connected an account already.

Select your Remix application's GitHub repository from the list of available repositories:

![Remix Project Vercel](https://cdn.hashnode.com/res/hashnode/image/upload/v1661198975722/53KKQBDVu.png)

This will bring you to a page where you can configure the deployment.

On this page, expand the **Environment Variables** section and add a `SANITY_API_URL` environment variable, using the Sanity GraphQL API URL as the value:

![Sanity URL Environment Variable](https://cdn.hashnode.com/res/hashnode/image/upload/v1661199099290/XjjP-17Qm.png)

Be sure to click **Add** after filling in the variable's details.

> **Note** : If you are unsure about what to input for the environment variable's value, check the value you used in your `.env` file.

Finally, you can hit **Deploy** to deploy your application. This will kick off the Remix project's build process and deploy the application to a live URL!

When that finishes up, you will be sent to a page that looks like this:

![Vercel Deployed](https://cdn.hashnode.com/res/hashnode/image/upload/v1661199300639/ltzI5GfMP.png)

If you click the image preview of your site, a new tab will open to your newly deployed website!

![Live Application](https://cdn.hashnode.com/res/hashnode/image/upload/v1661199379727/N9uDdDwzX.png)

## Deploy the Sanity project

The steps to deploy your Sanity application are all exactly the same, except you do not have to add an environment variable.

Head back over to the [Vercel dashboard](https://vercel.com/dashboard) and click the **Add New...** button again, selecting the **Project** option from the dropdown.

You will again be redirected to a page where you can select with GitHub repository you want to deploy. Choose the repository that holds your Sanity project:

![New Vercel Project](https://cdn.hashnode.com/res/hashnode/image/upload/v1661199659099/z7knGsKNF.png)

On the next page, simply hit the **Deploy** button to deploy the Sanity Studio:

![Deploy Sanity Studio](https://cdn.hashnode.com/res/hashnode/image/upload/v1661199707019/IQFtZ4IBm.png)

Once the deployment completes, open up the live site to see what it looks like:

![Sanity Broken](https://cdn.hashnode.com/res/hashnode/image/upload/v1661200230963/QhcY9pup2.png)

Oops... this doesn't look right! This problem occurred because Sanity is currently only accessible through `localhost`.

Head over to your local Sanity project's directory via a terminal and run the following command, replacing `<YOUR_APP_URL>` with the URL of your deployed studio:

```
# /Documents/projects/catalog-sanity
sanity cors add <YOUR_APP_URL> --credentials
# Example: sanity cors add https://book-catalog-sanity-ffwumik6d-sabinadams.vercel.app/desk --credentials

```

If you now head back to the browser and refresh, you should reach the Sanity Studio login page. Upon logging in, you will see your studio:

![Sanity Live and Working](https://cdn.hashnode.com/res/hashnode/image/upload/v1661200428697/0IkqVK5AP.png)

# Wrapping Up

Throughout this tutorial you accomplished a lot!

Just to recap, throughout this tutorial you:

- Built a Sanity project to host your book catalog data
- Built a Remix application to retrieve and render your data
- Added both projects to GitHub
- Deployed both projects with Vercel

The end result is an easy-to-use book catalog, where you can at any time log in to your Sanity Studio from your web browser and add records to your book catalog without having to re-deploy the Remix application.

Tools like Sanity are super powerful, especially when you have complex content and/or multiple types of content to manage. They allow you to easily manage your data in an environment completely separate from your application.

If you have any questions, please feel free to reach out to me on [Twitter](https://twitter.com/sabinthedev)!