Studio

Hosting and deployment

How to deploy Sanity Studio, either on your own or using our hosted service.

Sanity Studio is an open-source React-based Single Page Application (SPA) that runs entirely in the browser and connects with Sanity's hosted APIs and Content Lake.

There are two primary ways of hosting Sanity Studio:

  • Sanity hosting: Sanity serves the studio for you at a my-company.sanity.studio URL. One Sanity CLI command deploys it, and you can deploy and manage multiple studios for different environments or use cases under the same project.
  • Self-hosting: you deploy the studio to any hosting platform that supports single-page application (SPA) routing.

Sanity hosting is the quickest way to make your studio accessible on the web. Self-hosting is the better fit when you want platform-specific features that Sanity hosting doesn't offer, or when you want the studio on your own domain.

Prerequisites

This page assumes:

  • A Sanity project and a studio you can build locally.
  • The Sanity CLI, run through npx sanity@latest so that you're on the current version.
  • For self-hosting: a host you control that supports single-page application routing, and permission to add its domain to the project's CORS origins.

The --external, --url, --no-build, and --schema-required flags on sanity deploy require a recent Sanity CLI, which npx sanity@latest always resolves to.

Host with Sanity

Running this command from your studio project folder builds and deploys your studio, making it available on a *.sanity.studio URL. When you deploy, you're asked to choose a unique hostname for your studio. Deployed studios also appear in Dashboard.

Allowed characters in a studio hostname

You're also prompted to add your appId to your CLI configuration. This is optional. Adding it gives you fine-grained control over how and when your studio auto-updates, in the project management settings.

Studio access

Deployment size limit

Undeploy the studio

Run npx sanity@latest undeploy from your studio folder to change the hostname later, or to remove the studio from the web. The hostname is released asynchronously, so it can take a few minutes to become unavailable. After that, you can choose a new one the next time you deploy.

The undeploy command resolves the target from deployment.appId first, then studioHost, in your sanity.cli.ts configuration. Use the environment variable strategy under Host with Sanity in a CI/CD flow if you want to deploy and undeploy different studio instances.

Host with Sanity in a CI/CD flow

You can host with Sanity automatically with continuous integration tools. This is convenient for updating the hosted studio when you push local changes to a source repository, or when you do manual releases. Add sanity as a development dependency and configure your CI/CD workflow to run sanity deploy. Keep the sanity.cli.ts config file in your studio folder.

If you need to accommodate test, staging, and production deployments, define deployment.appId and any other configuration in environment variables, then read them in the config file:

Authorize studio deployments

You also need to provide an authorization token in the SANITY_AUTH_TOKEN environment variable. sanity deploy authenticates with your local user session, which isn't available in a CI/CD workflow. Create a deploy token in the project management dashboard.

Deploy pre-built studios

If your CI/CD pipeline builds the studio in a separate step, use --no-build to skip the build and deploy the existing dist/ directory:

Schema extraction and manifest upload still run during deploy, and the manifest is written into dist/static, so the command modifies the directory rather than leaving it untouched. dist/ must exist before you run this command. --no-build applies to Sanity-hosted deploys only: --external never builds, and the two flags can't be combined. See Deploy for the full pipeline.

Self-host the studio

Since the studio consists of static HTML, CSS, and JavaScript files and communicates with Sanity through our HTTP API, it can be hosted anywhere. Popular hosting services like Vercel and Netlify make it possible to automatically deploy new versions of your studio when you push it to a code repository like GitHub.

Two things have to be true when you host the studio yourself or with a service:

  • The server that delivers the studio files has to be configured for single-page application routing. If the requested URL path doesn't exist on the filesystem, it should serve index.html so the frontend router can handle the request. Most hosting services have a configuration option for this.
  • The domain where the studio is hosted has to be added as a valid domain in the project's CORS settings. For security, the Sanity API ensures that only approved studios can communicate with your project. This is in addition to other security measures such as user authentication, private datasets, and custom access rules.

If you host with Sanity, both are handled for you. If your host doesn't support single-page application routing, add a redirect rule so non-existent paths resolve to index.html. Check the documentation for your provider or server software.

Self-hosted studios must be registered

Specify the base path

Normally, the studio expects to be hosted at the root level of its hostname, for instance https://studio.example.com/. To serve the studio on a subpath, such as https://example.com/studio, you need to edit the CLI configuration file. You'll find it as sanity.cli.js or sanity.cli.ts in the root of your studio project.

The studio can now be served from https://example.com/studio. This also changes the base path of static files.

Most cases where you embed the studio in another application require you to set basePath.

The CLI and workspace base paths are joined

Setting the SANITY_STUDIO_BASEPATH environment variable is an alternative way to define the base path for the studio, and it overrides any value set in the configuration file. The CLI warns you when both are set.

Build the studio for hosting

Run npx sanity@latest build from your studio folder to generate the files for hosting. This outputs the files to the dist/ directory by default. Sometimes your environment requires another directory name, for instance public. You can specify this by entering the desired name after the build command.

Once the build is complete, the directory can be uploaded and hosted from any web host where you can control redirects for a single-page application, like Vercel, Netlify, or Cloudflare.

Register the studio and deploy the schema

One command does both jobs. sanity deploy --external records where your studio is served and deploys the workspace schema in the same run. It uploads no files, and it doesn't build: --external can't be combined with the build flags, so sanity build stays a separate step.

Without this step, the features that resolve a workspace, including Dashboard, Canvas, Media Library, and Agent Actions, can't discover your studio or its schema.

After building your studio and uploading the files to your own host, register it:

Run npx sanity@latest schemas deploy only when you want to update the schema without deploying a studio, such as a schema-only pipeline. See Schema deployment for its options.

--external tells Sanity that the studio is hosted somewhere other than Sanity's own hosting, so nothing is uploaded. It records the studio's location and links it to the schema deployed in the same run, which is what makes the studio resolvable from Dashboard, Media Library, Canvas, and the App SDK.

By default, a schema failure inside deploy is reported but doesn't stop the deployment, and the command still exits 0. Add --schema-required in a pipeline so that a schema failure fails the command.

--url takes the full URL where the studio is served, including any base path. If you set a basePath of /studio, as covered under Specify the base path, the registered URL has to include it.

You can set studioHost in sanity.cli.ts instead of passing --url on every run. For an external studio, the CLI validates it as a full URL and uses it as the registered location.

studioHost is deprecated in favor of deployment.appId, which takes precedence when both are set. deployment.appId identifies the application; the URL still comes from --url or studioHost.

Run this command on every deployment. Registration itself is idempotent and persists, so --url is only needed on the first run or when the URL changes. What each run updates is the schema and the manifest. See the Deploy CLI command reference for the full option list.

Environment variables

Sometimes you want to configure the projectId, dataset, or studioHost specified in sanity.cli.ts and sanity.config.ts at build time. This is useful for building multiple studios from the same schema and code, for different environments. See the documentation on environment variables for your options.

Errors you might see when deploying

Two of the most common failures come from the values you pass to the deploy command:

  • Hostnames can only contain letters, numbers, and hyphens. The hostname you chose uses characters outside that set, or starts or ends with a hyphen.
  • URL must use http or https protocol. The value passed to --url isn't an http or https URL. The same check runs on a studioHost set in the config file when you deploy with --external.

Two more to expect: --no-build fails when the output directory holds no built studio, and any deploy fails when the CLI can't find a project ID, which it reads from api.projectId in sanity.cli.ts.

Manage registered studios

Every studio registered to a project is listed on the project's Studios tab in Sanity Manage. The list covers studios deployed with sanity deploy and self-hosted studios registered with sanity deploy --external. Each row links to that studio, and the row's context menu lets you rename it, control whether it appears in Dashboard, and remove it from the project.

How the Open Sanity Studio button picks a destination

The project page in Manage shows a single button for opening a studio. Its destination is a rule rather than a setting, so you can't pin it to a particular studio. Manage resolves it from the studios registered to the project:

  • No registered studios: no button appears.
  • Exactly one self-hosted studio: Open Sanity Studio opens that studio, no matter how many Sanity-hosted studios are also registered.
  • No self-hosted studios and exactly one Sanity-hosted studio: Open Sanity Studio opens that studio.
  • Any other combination, such as two self-hosted studios or two Sanity-hosted studios and no self-hosted one: View Studios appears instead and links to the Studios tab.

Because a single self-hosted studio takes precedence, registering one changes where the button goes. This is expected behavior, not a regression. To reach a specific studio regardless of the rule, open it from its row on the Studios tab.

Dashboard visibility doesn't change the button

Remove a studio from a project

On the Studios tab, open a studio's context menu, click Remove studio, and confirm. Removing a studio de-registers it from the project and can't be undone. To register a self-hosted studio again, run npx sanity@latest deploy --external from the studio folder.

For a self-hosted studio, removing the entry affects the registration only:

  • Your hosting keeps serving the studio at its own URL. Your datasets, content, and any in-progress edits are untouched. They live in Content Lake, independent of this list.
  • The studio no longer appears in Dashboard, and features that rely on its registered schema, including Content Agent, Canvas, and Agent Actions, can no longer reach it.
  • The studio stops counting toward the button rule, which can change what the project page shows.

Taking a Sanity-hosted studio offline

GraphQL

Deploying a GraphQL API is covered in the GraphQL documentation.

Next steps

Was this page helpful?