
Security News
GitHub Actions Pricing Whiplash: Self-Hosted Actions Billing Change Postponed
GitHub postponed a new billing model for self-hosted Actions after developer pushback, but moved forward with hosted runner price cuts on January 1.
@sanity/svelte-loader
Advanced tools
[](https://npm-stat.com/charts.html?package=@sanity/svelte-loader) [](https://www
A Sanity loader for Svelte and SvelteKit.
Loaders provide a convenient, unified way of loading data across production, development and preview states, for both server and client side rendering. They also handle the heavy lifting of implementing Visual Editing alongside Presentation.
Read more about loaders here.
npm install @sanity/svelte-loader
# We will also need the following dependencies for fetching data and enabling visual editing
npm install @sanity/client @sanity/visual-editing
Use the steps below with an existing or new SvelteKit app to enable visual editing using the Svelte loader.
Create a .env file in the project's root directory and provide the following environment variables. The token should not be exposed on the client, so the PUBLIC_ prefix is omitted.
# .env
SANITY_API_READ_TOKEN="..."
PUBLIC_SANITY_PROJECT_ID="..."
PUBLIC_SANITY_DATASET="..."
PUBLIC_SANITY_API_VERSION="..."
PUBLIC_SANITY_STUDIO_URL="..."
Create and export an instance of Sanity client using the previously defined environment variables.
// src/lib/sanity.ts
import {createClient} from '@sanity/client'
import {
PUBLIC_SANITY_API_VERSION,
PUBLIC_SANITY_DATASET,
PUBLIC_SANITY_PROJECT_ID,
PUBLIC_SANITY_STUDIO_URL,
} from '$env/static/public'
export const client = createClient({
projectId: PUBLIC_SANITY_PROJECT_ID,
dataset: PUBLIC_SANITY_DATASET,
apiVersion: PUBLIC_SANITY_API_VERSION,
useCdn: true,
stega: {
studioUrl: PUBLIC_SANITY_STUDIO_URL,
},
})
On the server, we use a Sanity client configured with a read token to allow the fetching of preview content.
// src/lib/server/sanity.ts
import {SANITY_API_READ_TOKEN} from '$env/static/private'
import {client} from '$lib/sanity'
export const serverClient = client.withConfig({
token: SANITY_API_READ_TOKEN,
// Optionally enable stega
// stega: true
})
We pass the server client instance to setServerClient in the server hooks file as this code will only be executed once during app initialization.
The loader package also exports an optional createRequestHandler for creating a server hook handle function which:
locals.preview to true or false.locals.loadQuery, the function we will use to fetch data on the server.// src/hooks.server.ts
import {createRequestHandler, setServerClient} from '@sanity/svelte-loader'
import {serverClient} from '$lib/server/sanity'
setServerClient(serverClient)
export const handle = createRequestHandler()
[!NOTE] If our app needs to support multiple
handlefunctions, we can use SvelteKit's sequence function.
createRequestHandler adds properties to the event.locals object. When using TypeScript, we should add these to our app's App.Locals interface.
// app.d.ts
import type {LoaderLocals} from '@sanity/svelte-loader'
declare global {
namespace App {
interface Locals extends LoaderLocals {}
}
}
export {}
To access the preview state on the client side of our application, we pass it via a load function. Typically, the root level layout is a good place to do this. We return the value of locals.preview that the previously created handle function defines for us.
// src/routes/+layout.server.ts
import type {LayoutServerLoad} from './$types'
export const load: LayoutServerLoad = ({locals: {preview}}) => {
return {preview}
}
We then access the passed preview value via the LoadEvent.data property, and set the preview state using the loader's setPreviewing function.
// src/routes/+layout.ts
import {setPreviewing} from '@sanity/svelte-loader'
import type {LayoutLoad} from './$types'
export const load: LayoutLoad = ({data: {preview}}) => {
setPreviewing(preview)
}
We can now import isPreviewing (a readonly Svelte store) anywhere in our app. For example, in a component to display if previews are enabled or disabled:
<!-- src/components/DisplayPreview.svelte -->
<script lang="ts">
import { isPreviewing } from '@sanity/svelte-loader'
</script>
{#if $isPreviewing}
<div>Previews Enabled</div>
{:else}
<div>Previews Disabled</div>
{/if}
Next, create a queries file and define a GROQ query and associated result type. This example query is used to fetch a single page with a matching slug.
// src/lib/queries.ts
export const pageQuery = `*[_type == "page" && slug.current == $slug][0]`
export interface PageResult {
title: string
// ...etc
}
Create a server load function for our page that will handle fetching data from the Sanity Content Lake. Use locals.loadQuery to fetch data on the server.
// src/routes/[slug]/+page.server.ts
import {pageQuery, type PageResult} from '$lib/queries'
import type {PageServerLoad} from './$types'
export const load: PageServerLoad = async ({params, locals: {loadQuery}}) => {
const {slug} = params
const initial = await loadQuery<PageResult>(pageQuery, {slug})
return {initial, params: {slug}}
}
Next, create the page component. We use useQuery on the client, passing the initial data and route parameters that were returned by the load function. When live editing is enabled, useQuery will provide near instant updates from Content Lake and seamless switching between draft and published content.
useQuery also returns an encodeDataAttribute helper method for generating data-sanity attributes to support rendering overlays.
<!-- src/routes/[slug]/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types'
import { useQuery } from '@sanity/svelte-loader'
import { pageQuery, type PageResult } from '$lib/queries'
export let data: PageData
const { initial, params } = data;
const query = useQuery<PageResult>(pageQuery, params, { initial })
const studioUrl = 'https://my.sanity.studio'
$: ({ data: page, loading, encodeDataAttribute } = $query)
</script>
{#if loading}
<div>Loading...</div>
{:else}
<h1 data-sanity={encodeDataAttribute(['title'])}>
{page.title}
</h1>
{/if}
Finally, we enable both live mode and overlays in the root layout component.
<!-- src/routes/+layout.svelte -->
<script lang="ts">
import { onMount } from 'svelte'
import { enableVisualEditing } from '@sanity/visual-editing'
import { useLiveMode } from '@sanity/svelte-loader'
import { client } from '$lib/sanity'
import { PUBLIC_SANITY_STUDIO_URL } from '$env/static/public'
onMount(() => enableVisualEditing())
onMount(() => useLiveMode({
// If `stega.studioUrl` was not provided to the client instance in `sanity.ts`, a studioUrl should be provided here
studioUrl: PUBLIC_SANITY_STUDIO_URL
// ...or alternatively provide the stega client directly
// client: client.withConfig({
// stega: true
// })
}))
</script>
<div class="app">
<slot />
</div>
FAQs
[](https://npm-stat.com/charts.html?package=@sanity/svelte-loader) [](https://www
The npm package @sanity/svelte-loader receives a total of 292 weekly downloads. As such, @sanity/svelte-loader popularity was classified as not popular.
We found that @sanity/svelte-loader demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 109 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub postponed a new billing model for self-hosted Actions after developer pushback, but moved forward with hosted runner price cuts on January 1.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.