This episode covers how to make a Svelte app faster: profiling with browser tools and benchmarks, minimizing the bundle with tree-shaking, reducing runtime overhead and reactivity costs, and lazy loading components and code splitting.

Optimization without measurement is just guessing. Before chasing micro-optimizations, it's important to know where time is really wasted — whether it's a heavy bundle, expensive renders, or slow requests.
This episode covers profiling with browser tools and benchmarks, minimizing the bundle with tree-shaking, reducing runtime overhead and reactivity costs, and lazy loading components and code splitting.
When you're done, you'll have a clear workflow: measure, find the biggest problem, fix it, and measure again. Optimization becomes a repeatable, measurable process instead of aimlessly shuffling problems around.
One principle underlies this entire episode: measure the impact of a change after it's done, not just when you start. Before and after numbers are the only proof an optimization actually worked.
Chrome DevTools provides a Performance panel to record activity while a page runs. The recording shows where CPU is spent: slow functions, expensive layouts, and janky paints. Start with the flow your users use most often.
Improve recording quality by enabling CPU throttling in the Performance panel to simulate a mid-range device. Optimizations that look great on a developer laptop may not be felt on user devices.
Lighthouse provides measurable scores for performance, accessibility, and SEO. Run it regularly in CI so regressions are caught early. Scores aren't the end goal, but a compass for where to improve.
It's hard to optimize something you can't see. vite-bundle-visualizer produces an interactive map of each module's size:
npm install -D vite-bundle-visualizer
npx vite-bundle-visualizerThe result is a treemap chart showing the largest libraries. The target is usually one or two giant modules — not many small ones.
Tree-shaking removes unused code at build time. For it to work, use named imports instead of importing an entire library. For example, import { writable } from "svelte/store" is far friendlier than an import that drags in the whole module. Also make sure the libraries you use declare the correct sideEffects in package.json.
Also check whether the libraries you use already take advantage of ES module exports. Modern builds need that format so the bundler can safely cut unused parts.
Svelte turns reactive declarations into precise update code. The more things you make reactive, the more work the compiler has to track. Limit $: statements to values that truly derive from their source:
let query = ""
let hasil = []
$: if (query.length >= 3) {
hasil = cari(query)
}This reactive statement only runs cari(query) when query changes and only if its length is sufficient. The Svelte compiler generates code that compares values before marking a change, so updates that don't alter the result never touch the DOM.
Beware of mass updates when data changes. If a statement triggers many consecutive updates, consider deferring the computation until the data has finished changing.
Inside {#each}, avoid creating a new object or array each iteration. New objects force reactivity to compare new values every time, while also adding garbage collector pressure. Build static data outside the template or in a value computed once.
The same pattern applies to functions called in the template. A function that allocates a new object every render will be re-run on every potential update.
Editor, chart, or video player components don't need to load on the first page. Dynamic imports split the code and load a module only when it's needed:
<script>
let Editor = null
import("$lib/components/Editor.svelte").then((mod) => {
Editor = mod.default
})
</script>
{#if Editor}
<svelte:component this={Editor} />
{/if}import("$lib/components/Editor.svelte") produces a separate chunk that downloads after the main page finishes loading. Everything else runs without waiting for the heavy component — perceived speed rises even if the total bytes downloaded are similar.
Use sensible thresholds. Don't split small components into dozens of chunks — too many small requests actually slow things down. Split only what's heavy and rarely used.
SvelteKit supports waiting for parallel data inside load functions. Components that depend on heavy data can also be rendered conditionally with the {#await} block so first content appears faster.
Key takeaways:
vite-bundle-visualizer to find the largest modules.sideEffects declarations support tree-shaking.{#each} loops.Next, in episode 16 you'll learn testing & quality — unit testing with Vitest and Svelte Testing Library, integration testing for SvelteKit apps, E2E testing with Playwright, and static analysis, linting, and type checking. Your optimized code must be guaranteed to stay correct through automated testing.