{"id":16494866,"url":"https://github.com/stipsan/next-sanity-preview","last_synced_at":"2025-04-04T18:14:21.851Z","repository":{"id":66053915,"uuid":"524111936","full_name":"stipsan/next-sanity-preview","owner":"stipsan","description":null,"archived":false,"fork":false,"pushed_at":"2023-12-15T02:46:08.000Z","size":472,"stargazers_count":2,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-10T03:22:38.951Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"next-sanity-preview.vercel.app","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stipsan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-08-12T14:11:11.000Z","updated_at":"2023-03-04T05:53:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"355bf272-097e-4bec-abee-63edf2a3f985","html_url":"https://github.com/stipsan/next-sanity-preview","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stipsan%2Fnext-sanity-preview","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stipsan%2Fnext-sanity-preview/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stipsan%2Fnext-sanity-preview/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stipsan%2Fnext-sanity-preview/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stipsan","download_url":"https://codeload.github.com/stipsan/next-sanity-preview/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226193,"owners_count":20904465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T14:16:02.340Z","updated_at":"2025-04-04T18:14:21.830Z","avatar_url":"https://github.com/stipsan.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A statically generated blog example using Next.js and Sanity\n\nThis example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [Sanity](https://www.sanity.io/) as the data source.\n\nYou'll get:\n\n- Next.js deployed with the [Sanity Vercel Integration][integration].\n- Sanity Studio running on localhost and deployed in the [cloud](https://www.sanity.io/docs/deployment).\n- Sub-second as-you-type previews in Next.js\n- [On-demand revalidation of pages](https://nextjs.org/blog/next-12-1#on-demand-incremental-static-regeneration-beta) with [GROQ powered webhooks](https://www.sanity.io/docs/webhooks)\n\n## Demo\n\n### [https://next-blog-sanity.vercel.app](https://next-blog-sanity.vercel.app)\n\n## Related examples\n\n- [WordPress](/examples/cms-wordpress)\n- [DatoCMS](/examples/cms-datocms)\n- [TakeShape](/examples/cms-takeshape)\n- [Prismic](/examples/cms-prismic)\n- [Contentful](/examples/cms-contentful)\n- [Strapi](/examples/cms-strapi)\n- [Agility CMS](/examples/cms-agilitycms)\n- [Cosmic](/examples/cms-cosmic)\n- [ButterCMS](/examples/cms-buttercms)\n- [Storyblok](/examples/cms-storyblok)\n- [GraphCMS](/examples/cms-graphcms)\n- [Kontent](/examples/cms-kontent)\n- [Ghost](/examples/cms-ghost)\n- [Umbraco Heartcore](/examples/cms-umbraco-heartcore)\n- [Blog Starter](/examples/blog-starter)\n- [Builder.io](/examples/cms-builder-io)\n\n# Configuration\n\n- [Step 1. Set up the environment](#step-1-set-up-the-environment)\n- [Step 2. Configure CORS for localhost](#step-2-configure-cors-for-localhost)\n- [Step 3. Run Next.js locally in development mode](#step-3-run-nextjs-locally-in-development-mode)\n- [Step 4. Populate content](#step-4-populate-content)\n- [Step 5. Deploy to production \u0026 use Preview Mode from anywhere](#step-5-deploy-to-production--use-preview-mode-from-anywhere)\n  - [If you didn't Deploy with Vercel earlier do so now](#if-you-didnt-deploy-with-vercel-earlier-do-so-now)\n  - [Configure CORS for production](#configure-cors-for-production)\n  - [Add the preview secret environment variable](#add-the-preview-secret-environment-variable)\n  - [How to test locally that the secret is setup correctly](#how-to-test-locally-that-the-secret-is-setup-correctly)\n  - [How to start Preview Mode for Next.js in production from a local Studio](#how-to-start-preview-mode-for-nextjs-in-production-from-a-local-studio)\n  - [If you regret sending a preview link to someone](#if-you-regret-sending-a-preview-link-to-someone)\n- [Step 6. Deploy your Studio and publish from anywhere](#step-6-deploy-your-studio-and-publish-from-anywhere)\n- [Step 7. Setup Revalidation Webhook](#step-7-setup-revalidation-webhook)\n  - [Testing the Webhook](#testing-the-webhook)\n- [Next steps](#next-steps)\n\n## Step 1. Set up the environment\n\nUse the Deploy Button below, you'll deploy the example using [Vercel](https://vercel.com?utm_source=github\u0026utm_medium=readme\u0026utm_campaign=next-example) as well as connect it to your Sanity dataset using [the Sanity Vercel Integration][integration].\n\n[![Deploy with Vercel](https://vercel.com/button)][vercel-deploy]\n\n[Clone the repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) that Vercel created for you and from the root directory of your local checkout.\nThen link your clone to Vercel:\n\n```bash\nnpx vercel link\n```\n\nDownload the environment variables needed to connect Next.js and Studio to your Sanity project:\n\n```bash\nnpx vercel env pull\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eYou can also set up manually\u003c/summary\u003e\n\n- [Bootstrap the example](#bootstrap-the-example)\n- [Connect to a Sanity project](#connect-to-a-sanity-project)\n- [Set up environment variables](#set-up-environment-variables)\n\nIf using the [integration] isn't an option. Or maybe you want to work locally first and deploy to Vercel later. Whatever the reason this guide shows you how to setup manually.\n\n### Bootstrap the example\n\nExecute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io):\n\n```bash\nnpx create-next-app --example cms-sanity cms-sanity-app\n```\n\n```bash\nyarn create next-app --example cms-sanity cms-sanity-app\n```\n\n```bash\npnpm create next-app --example cms-sanity cms-sanity-app\n```\n\n### Connect to a Sanity project\n\nRun this to select from your existing Sanity projects, or create a new one:\n\n```bash\n(cd studio \u0026\u0026 npx @sanity/cli init)\n```\n\nThe CLI will update [`sanity.json`] with the project ID and dataset name.\n\n### Set up environment variables\n\nCopy the [`.env.local.example`] file in this directory to `.env.local` (which will be ignored by Git):\n\n```bash\ncp .env.local.example .env.local\n```\n\nThen set these variables in `.env.local`:\n\n- `NEXT_PUBLIC_SANITY_PROJECT_ID` should be the `projectId` value from [`sanity.json`].\n- `NEXT_PUBLIC_SANITY_DATASET` should be the `dataset` value from [`sanity.json`].\n- `SANITY_API_READ_TOKEN` create an API token with `read-only` permissions:\n  - Run this to open your project settings or go to https://manage.sanity.io/ and open your project:\n    ```bash\n    (cd studio \u0026\u0026 npx @sanity/cli manage)\n    ```\n  - Go to **API** and the **Tokens** section at the bottom, launch its **Add API token** button.\n  - Name it `SANITY_API_READ_TOKEN`, set **Permissions** to `Viewer`.\n  - Hit **Save** and you can copy/paste the token.\n\nYour `.env.local` file should look like this:\n\n```bash\nNEXT_PUBLIC_SANITY_PROJECT_ID=...\nNEXT_PUBLIC_SANITY_DATASET=...\nSANITY_API_READ_TOKEN=...\n```\n\n\u003c/details\u003e\n\n## Step 2. Configure CORS for localhost\n\nNeeded for live previewing unpublished/draft content.\n\n```bash\nnpm --prefix studio run cors:add -- http://localhost:3000 --credentials\n```\n\n## Step 3. Run Next.js locally in development mode\n\n```bash\nnpm install \u0026\u0026 npm run dev\n```\n\n```bash\nyarn install \u0026\u0026 yarn dev\n```\n\nYour blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).\n\n## Step 4. Populate content\n\nIn another terminal start up the studio:\n\n```bash\nnpm run studio:dev\n```\n\nYour studio should be up and running on [http://localhost:3333](http://localhost:3333)!\n\nCreate content in Sanity Studio and live preview it in Next.js, side-by-side, by opening these URLs:\n\n- [`http://localhost:3333`](http://localhost:3333)\n- [`http://localhost:3000/api/preview`](http://localhost:3000/api/preview)\n\n\u003cdetails\u003e\n\u003csummary\u003eView screenshot ✨\u003c/summary\u003e\n\n![screenshot](https://user-images.githubusercontent.com/81981/182991870-7a0f6e54-b35e-4728-922b-409fcf1d6cc3.png)\n\n\u003c/details\u003e\n\nWe're all set to do some content creation!\n\n- Click on the **\"Create new document\"** button top left and select **Post**\n- Type some dummy data for the **Title**\n- **Generate** a **Slug**\n  \u003cdetails\u003e\n  \u003csummary\u003eView screenshot ✨\u003c/summary\u003e\n\n  ![screenshot](https://user-images.githubusercontent.com/81981/182993687-b6313086-f60a-4b36-b038-4c1c63b53c54.png)\n\n  \u003c/details\u003e\n\n- Set the **Date**\n- Select a **Cover Image** from [Unsplash].\n  \u003cdetails\u003e\n  \u003csummary\u003eView screenshot ✨\u003c/summary\u003e\n\n  ![screenshot](https://user-images.githubusercontent.com/81981/182994571-f204c41c-e1e3-44f4-82b3-99fefbd25bec.png)\n\n  \u003c/details\u003e\n\n- Let's create an **Author** inline, click **Create new**.\n- Give the **Author** a **Name**.\n- After selecting a **Picture** of a **face** from [Unsplash], set a hotspot to ensure pixel-perfect cropping.\n  \u003cdetails\u003e\n  \u003csummary\u003eView screenshot ✨\u003c/summary\u003e\n\n  ![screenshot](https://user-images.githubusercontent.com/81981/182995772-33d63e45-4920-48c5-aa47-ccb7ce10170c.png)\n\n  \u003c/details\u003e\n\n- Create a couple more **Posts** and watch how the layout adapt to more content.\n\n**Important:** For each post record, you need to click **Publish** after saving for it to be visible outside Preview Mode.\n\nTo exit Preview Mode, you can click on _\"Click here to exit preview mode\"_ at the top.\n\n## Step 5. Deploy to production \u0026 use Preview Mode from anywhere\n\n### If you didn't [Deploy with Vercel earlier](#step-1-set-up-the-environment) do so now\n\nTo deploy your local project to Vercel, push it to [GitHub](https://docs.github.com/en/get-started/importing-your-projects-to-github/importing-source-code-to-github/adding-locally-hosted-code-to-github)/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github\u0026utm_medium=readme\u0026utm_campaign=next-example).\n\n**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file.\n\nAfter it's deployed link your local code to the Vercel project:\n\n```bash\nnpx vercel link\n```\n\n### Configure CORS for production\n\nAdd your `production url` to the list over CORS origins.\n\n\u003cdetails\u003e\n\u003csummary\u003eDon't remember the production url? 🤔\u003c/summary\u003e\n\nNo worries, it's easy to find out. Go to your [Vercel Dashboard](https://vercel.com/) and click on your project:\n\n![screenshot](https://user-images.githubusercontent.com/81981/183002637-6aa6b1d8-e0ee-4a9b-bcc0-d49799fcc984.png)\n\nIn the screenshot above the `production url` is `https://cms-sanity.vercel.app`.\n\n\u003c/details\u003e\n\n```bash\nnpm --prefix studio run cors:add -- [your production url] --credentials\n```\n\n### Add the preview secret environment variable\n\nIt's required to set a secret that makes Preview Mode activation links unique. Otherwise anyone could see your unpublished content by just opening `[your production url]/api/preview`.\nRun this and it'll prompt you for a value:\n\n```bash\nnpx vercel env add SANITY_STUDIO_PREVIEW_SECRET\n```\n\nThe secret can be any combination of random words and letters as long as it's URL safe.\nYou can generate one in your DevTools console using `copy(Math.random().toString(36).substr(2, 10))` if you don't feel like inventing one.\n\nYou should see something like this in your terminal afterwards:\n\n```bash\n$ npx vercel env add SANITY_STUDIO_PREVIEW_SECRET\nVercel CLI 27.3.7\n? What’s the value of SANITY_STUDIO_PREVIEW_SECRET? 2whpu1jefs\n? Add SANITY_STUDIO_PREVIEW_SECRET to which Environments (select multiple)? Production, Preview, Development\n✅  Added Environment Variable SANITY_STUDIO_PREVIEW_SECRET to Project cms-sanity [1s]\n```\n\nRedeploy production to apply the secret to the preview api:\n\n```bash\nnpx vercel --prod\n```\n\nAfter it deploys it should now start preview mode if you launch `[your production url]/api/preview?secret=[your preview secret]`. You can send that preview url to people you want to show the content you're working on before you publish it.\n\n### How to test locally that the secret is setup correctly\n\nIn order to test that the secret will prevent unauthorized people from activating preview mode, start by updating the local `.env` with the secret you just made:\n\n```bash\nnpx vercel env pull\n```\n\nRestart your Next.js and Studio processes so the secret is applied:\n\n```bash\nnpm run dev\n```\n\n```bash\nnpm run studio:dev\n```\n\nAnd now you'll get an error if `[secret]` is incorrect when you try to open `https://localhost:3000/api/preview?secret=[secret]`.\n\n### How to start Preview Mode for Next.js in production from a local Studio\n\nRun this to make the Studio open previews at `[your production url]/api/preview` instead of `http://localhost:3000/api/preview`\n\n```bash\nSANITY_STUDIO_PREVIEW_URL=[your production url] npm run studio:dev\n```\n\n### If you regret sending a preview link to someone\n\nRevoke their access by creating a new secret:\n\n```bash\nnpx vercel env rm SANITY_STUDIO_PREVIEW_SECRET\nnpx vercel env add SANITY_STUDIO_PREVIEW_SECRET\nnpx vercel --prod\n```\n\n## Step 6. Deploy your Studio and publish from anywhere\n\nLive previewing content is fun, but collaborating on content in real-time is next-level:\n\n```bash\nSANITY_STUDIO_PREVIEW_URL=[your production url] npm run studio:deploy\n```\n\nIf it's successful you should see something like this in your terminal:\n\n```bash\nSANITY_STUDIO_PREVIEW_URL=\"https://cms-sanity.vercel.app\" npm run studio:deploy\n? Studio hostname (\u003cvalue\u003e.sanity.studio): cms-sanity\n\nIncluding the following environment variables as part of the JavaScript bundle:\n- SANITY_STUDIO_PREVIEW_URL\n- SANITY_STUDIO_PREVIEW_SECRET\n- SANITY_STUDIO_API_PROJECT_ID\n- SANITY_STUDIO_API_DATASET\n\n✔ Deploying to Sanity.Studio\n\nSuccess! Studio deployed to https://cms-sanity.sanity.studio/\n```\n\nThis snippet is stripped from verbose information, you'll see a lot of extra stuff in your terminal.\n\n## Step 7. Setup Revalidation Webhook\n\nUsing GROQ Webhooks Next.js can rebuild pages that have changed content. It rebuilds so fast it can almost compete with Preview Mode.\n\nCreate a secret and give it a value the same way you did for `SANITY_STUDIO_PREVIEW_SECRET` in [Step 4](#add-the-preview-secret-environment-variable). It's used to verify that webhook payloads came from Sanity infra, and set it as the value for `SANITY_REVALIDATE_SECRET`:\n\n```bash\nnpx vercel env add SANITY_REVALIDATE_SECRET\n```\n\nYou should see something like this in your terminal afterwards:\n\n```bash\n$ npx vercel env add SANITY_REVALIDATE_SECRET\nVercel CLI 27.3.7\n? What’s the value of SANITY_REVALIDATE_SECRET? jwh3nr85ft\n? Add SANITY_REVALIDATE_SECRET to which Environments (select multiple)? Production, Preview, Development\n✅  Added Environment Variable SANITY_REVALIDATE_SECRET to Project cms-sanity [1s]\n```\n\nApply the secret to production:\n\n```bash\nnpx vercel --prod\n```\n\nWormhole into the [manager](https://manage.sanity.io/) by running:\n\n```bash\n(cd studio \u0026\u0026 npx @sanity/cli hook create)\n```\n\n- **Name** it \"On-demand Revalidation\".\n- Set the **URL** to`[your production url]/api/revalidate`, for example: `https://cms-sanity.vercel.app/api/revalidate`\n- Set the **Trigger on** field to \u003clabel\u003e\u003cinput type=checkbox checked\u003e Create\u003c/label\u003e \u003clabel\u003e\u003cinput type=checkbox checked\u003e Update\u003c/label\u003e \u003clabel\u003e\u003cinput type=checkbox checked\u003e Delete\u003c/label\u003e\n- Set the **Filter** to `_type == \"post\" || _type == \"author\"`\n- Set the **Secret** to the same value you gave `SANITY_REVALIDATE_SECRET` earlier.\n- Hit **Save**!\n\n### Testing the Webhook\n\n- Open the Deployment function log. (**Vercel Dashboard \u003e Deployment \u003e Functions** and filter by `api/revalidate`)\n- Edit a Post in your Sanity Studio and publish.\n- The log should start showing calls.\n- And the published changes show up on the site after you reload.\n\n## Next steps\n\n- Mount your preview inside the Sanity Studio for comfortable side-by-side editing\n- [Join the Sanity community](https://slack.sanity.io/)\n\n[vercel-deploy]: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fcms-sanity\u0026repository-name=cms-sanity\u0026project-name=cms-sanity\u0026demo-title=Blog%20using%20Next.js%20%26%20Sanity\u0026demo-description=On-demand%20ISR%2C%20sub-second%20as-you-type%20previews\u0026demo-url=https%3A%2F%2Fnext-blog-sanity.vercel.app%2F\u0026demo-image=https%3A%2F%2Fuser-images.githubusercontent.com%2F110497645%2F182727236-75c02b1b-faed-4ae2-99ce-baa089f7f363.png\u0026integration-ids=oac_hb2LITYajhRQ0i4QznmKH7gx\n[integration]: https://www.sanity.io/docs/vercel-integration\n[`sanity.json`]: studio/sanity.json\n[`.env.local.example`]: .env.local.example\n[unsplash]: https://unsplash.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstipsan%2Fnext-sanity-preview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstipsan%2Fnext-sanity-preview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstipsan%2Fnext-sanity-preview/lists"}