The July 2026 Svelte update brings a real shift in how SvelteKit projects are configured. SvelteKit config moves to vite.config.js — previewing how Kit 3 will work, explicit environment variables, full toolchain support for {const ...} declarations, and improvements to remote functions, prerendering, and the sv CLI.
July 2026 is a milestone month for the Svelte ecosystem. The SvelteKit team shipped nine feature releases (2.62.0 through 2.68.0) in a single month, while the Svelte CLI and language tools caught up with Svelte 5's latest syntax. The result is a significantly improved developer experience for anyone building with SvelteKit.
This article covers everything that landed this month: the SvelteKit config consolidation
that previews Kit 3, the experimental explicit environment variable system, full toolchain
support for {const ...} declaration tags, direct file uploads through remote
functions, prerendered Markdown precompression, and the improved sv CLI.
Whether you're evaluating SvelteKit for your next project or already building with it, these changes matter — particularly the config and environment variable improvements, which signal the direction of SvelteKit 3.
The biggest structural change this month: you can now define your SvelteKit
configuration directly inside vite.config.js, removing the need for
a separate svelte.config.js file (SvelteKit 2.62.0).
This is a preview of how SvelteKit 3 will require config to live in vite.config.js.
Instead of maintaining two config files, everything goes into your Vite config:
// svelte.config.js — no longer required (but still supported)
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default {
preprocess: vitePreprocess()
};
// vite.config.js — now the single source of truth
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit({
// SvelteKit config goes here
preprocess: vitePreprocess(),
kit: {
outDir: '.svelte-kit',
adapter: adapter()
}
})
]
});
The sv create scaffolding now generates projects with this setup by default
([email protected]), so new projects start with a single config file. The language
tools ([email protected] / [email protected]) can
also read Svelte config straight from vite.config.js/ts, so your editor
integrations continue working without svelte.config.js.
Existing projects: svelte.config.js continues to work in
SvelteKit 2.x. There's no immediate migration required. New projects:
sv create generates a single vite.config.js by default.
SvelteKit 3: the separate config file will be fully replaced. If you start
adopting the new pattern now, migration will be seamless.
SvelteKit 2.63.0 introduces experimental explicit environment variables.
Instead of relying on the $env/* virtual modules, you now declare and type
your environment variables in one place.
This is a significant architectural change. The $env/* modules have been
SvelteKit's environment variable interface since the beginning, but they have limitations:
no type safety (you get strings by default), no autocompletion in editors, and the module
system can be confusing for new developers.
The new approach uses a defineEnv helper that declares your env vars with
their types:
// src/lib/env.js
import { defineEnv } from '@sveltejs/kit/env';
export const env = defineEnv({
// Public env vars (exposed to the client)
public: {
VITE_API_URL: { type: 'string', default: 'https://api.example.com' },
VITE_APP_NAME: { type: 'string' }
},
// Private env vars (server-only)
private: {
DATABASE_URL: { type: 'string' },
STRIPE_SECRET_KEY: { type: 'string' },
MAX_UPLOAD_SIZE: { type: 'number', default: 5242880 }
}
});
Once declared, you import from your env.js file instead of using
$env/static/public or $env/dynamic/private. TypeScript
autocompletion and type checking work natively — your editor knows the shape of every
env var, including defaults.
// Instead of: import { PUBLIC_API_URL } from '$env/static/public';
import { env } from '$lib/env';
// Full type-safety — autocompletion works
const apiUrl = env.VITE_API_URL;
const dbUrl = env.DATABASE_URL;
The drizzle and better-auth CLI add-ons already support the new
explicit env var system, generating the correct declarations automatically
([email protected]). This is designed to eventually replace $env/*
entirely in SvelteKit 3.
SvelteKit 2.64.0 adds native File object support to remote function commands.
Previously, uploading a file through a remote function required manually wrapping it in
FormData. Now you can pass File objects directly:
// Before — manual FormData wrapping
import { uploadAvatar } from './api';
const formData = new FormData();
formData.append('avatar', fileInput.files[0]);
await uploadAvatar({ data: formData });
// After — direct File object
import { uploadAvatar } from './api';
await uploadAvatar({ file: fileInput.files[0] });
SvelteKit handles serialization automatically, making the code cleaner and removing a
common source of bugs. The server-side command receives the File object
natively.
SvelteKit 2.65.0 lets remote queries refresh other queries. This solves a common pain point: after mutating data (e.g., adding a comment), you want to refresh related queries (e.g., the comment list) without manual invalidation logic.
// query.js
export const getPosts = remote.query(async () => {
return db.select().from(posts);
});
export const getComments = remote.query(async (postId) => {
return db.select().from(comments).where(eq(comments.postId, postId));
});
// command.js — addComment refreshes both queries automatically
export const addComment = remote.command(async ({ postId, text }) => {
await db.insert(comments).values({ postId, text });
// This triggers a refresh of both queries on the client
return { refreshes: [getPosts, getComments(postId)] };
});
The refreshes property on the return value tells the client which queries
to re-fetch after the mutation succeeds. This eliminates the need for manual cache
invalidation or event-based refresh coordination.
SvelteKit 2.66.0 adds warnings when boolean fields in remote form schemas are not marked
optional — a common cause of silent submit failures. Version 2.68.0 exports
RemoteFormEnhanceInstance and RemoteFormEnhanceCallback types for
typed custom enhance callbacks, and submitted submit fields now
keep their value in the form action payload, making multi-button forms easier to handle on
the server.
SvelteKit 2.66.0 extends precompression to prerendered .md and
.mdx files. Previously, only HTML, JavaScript, and CSS assets were
precompressed (gzip, brotli) during the build. Now Markdown content also gets precompressed,
meaning faster delivery of documentation sites, blogs, and any site that prerenders
Markdown content.
Combined with adapter-static's precompress option, your
Markdown-based content now serves as efficiently as HTML. This is particularly valuable
for documentation sites generated from .md/.mdx files using
SvelteKit's content rendering pipeline.
SvelteKit 2.66.0 introduces a warning when boolean fields in remote form schemas are not marked optional. This is a subtle but important quality-of-life improvement:
// Without marking optional — now warns
const schema = {
agreeToTerms: 'boolean'
};
// When the checkbox is unchecked, no value is submitted,
// and the schema validation fails silently.
// Correct — mark as optional
const schema = {
agreeToTerms: { type: 'boolean', optional: true }
};
Unchecked checkboxes don't submit a value, which causes unexpected schema failures. The new warning catches this during development instead of leaving you to debug a mystery submit failure in production.
SvelteKit 2.67.0 adds prerender.handleInvalidUrl, giving you control over
how invalid URLs found during crawling are reported. You can now configure the behaviour
instead of accepting the default fail-fast approach:
// svelte.config.js (or vite.config.js plugin options)
export default {
kit: {
prerender: {
handleInvalidUrl: 'warn' // or 'ignore', or a custom function
}
}
};
This is useful for sites that link to external resources or have known URL patterns that the prerenderer can't resolve. Instead of the build failing, you can choose to warn or ignore specific patterns while still catching genuine broken links.
Svelte 5 introduced {const ...} declarations, which let you destructure and
transform data inline inside blocks like {#each}. Until this month, editor
tooling didn't fully support them — the language server, svelte-check, and
svelte2tsx either ignored or incorrectly handled the syntax.
The July update brings full toolchain support across the board:
{const ...} in the
demo template ([email protected]){const ...} for completions
and diagnostics ([email protected]){const ...}
declarations ([email protected]){const ...} to TypeScript
declarations ([email protected])Here's what the syntax looks like in practice:
{#each products as product}
{const {id, name, price, image} = product}
{const discounted = price * 0.9}
{name}
${price}
${discounted.toFixed(2)}
{/each}
Before this update, you'd either destructure in a <script> block or use
reactive $: statements. The {const ...} approach keeps the
template self-contained and makes the data flow explicit at the point of use.
The sv CLI received several meaningful upgrades in version 0.16.0:
sv create now scaffolds projects against @sveltejs/kit@^2.62.0
and moves the Svelte config into the Vite plugin by default. New projects start with a
single vite.config.js — no svelte.config.js needed.
A new experimental add-on lets you toggle experimental flags and opt into
@next versions directly from the CLI. Instead of manually editing config
files to try preview features, you can enable them interactively:
sv add experimental --flag explicit-env-vars
sv add experimental --next
The drizzle and better-auth add-ons now support SvelteKit's new
explicit environment variables. When you add these integrations, the CLI generates the
correct defineEnv declarations automatically — no manual wiring required.
New defineEnv and svelteConfig helpers in
@sveltejs/[email protected] make it easier for add-on authors to read and edit
a project's Svelte config programmatically. This lowers the barrier for building custom
add-ons.
The Svelte language server and related tools had their own improvements beyond
{const ...} support:
CSS completions now work inside nested <style> tags
([email protected]). If your Svelte component contains multiple
style blocks (e.g., a component-level style block and a scoped one), the editor now
provides correct CSS completions in both.
The language tools can now read Svelte config straight from
vite.config.js/ts ([email protected] /
[email protected]). This is the companion change to the config
consolidation — editor integrations work whether your config is in
svelte.config.js or inside the Vite plugin options.
An experimental tsgo option is available for faster type checking. This is
early-stage and not yet enabled by default, but it signals the Svelte team's interest in
reducing type checking overhead for large projects.
2.62.0 — SvelteKit config in vite.config.js (Kit 3 preview)
2.63.0 — Explicit environment variables (experimental)
2.64.0 — Direct File upload in remote functions
2.65.0 — Query refreshing in remote functions
2.66.0 — .md/.mdx precompression + boolean field warnings
2.67.0 — prerender.handleInvalidUrl option
2.68.0 — Exported types + submit field payload
sv CLI: 0.16.0
Language server: 0.18.1 / 0.18.2
svelte-check: 4.5.0 / 4.6.0
The July 2026 update makes SvelteKit more configurable, more type-safe, and better tooled than ever. Whether you're migrating from another framework or starting fresh, these improvements lower the barriers to building fast, maintainable web applications.
I work with SvelteKit alongside React, Vue.js, and Angular — choosing the right tool for each project. If you're planning a web application and want an experienced perspective, reach out to me. I provide free initial consultations to help you make the right technology choices.
I'm a full-stack developer with 20+ years of experience building web applications. Based in Minsk and working worldwide, let's discuss your project.
Tell me about your project — I'll recommend the best framework and provide a preliminary estimate. Free of charge.