We just shipped @flareapp/svelte, a Svelte 5 integration for Flare. It catches errors anywhere in your component tree, renders a fallback UI, and sends a report that includes the component name, its parent chain, and where in the lifecycle the error came from.
Before this, you might have wired up @flareapp/js by hand and leaned on its global window.onerror listener. That still works, and it still catches the error. What it doesn't know is anything about Svelte: which component broke, or whether the break happened during render, in an event handler, or inside an $effect. The new Svelte client fills this gap!
An error boundary built on snippets
The core of the package is FlareErrorBoundary. Wrap your full app or a small part, give it a failed snippet, and any error thrown inside it renders the fallback instead of taking down the whole page.
An example of wrapping your full app (with initialisation of the core Flare client):
<script lang="ts">
import { flare } from '@flareapp/js';
import { FlareErrorBoundary } from '@flareapp/svelte';
import Root from './Root.svelte';
if (import.meta.env.PROD) {
flare.light('YOUR_FLARE_API_KEY');
}
</script>
<FlareErrorBoundary>
<Root />
{#snippet failed(error, reset)}
<p>{error.message}</p>
<button onclick={reset}>Try again</button>
{/snippet}
</FlareErrorBoundary>
The failed snippet gets the error and a reset function. Call reset and the boundary re-renders its children, so the user can retry without a full page reload.
If you want a boundary to clear itself when state changes, pass resetKeys. When any value in the array changes, the boundary resets on its own. This is handy when you navigate between routes or switch the active record and don't want a stale error sticking around.
<FlareErrorBoundary resetKeys={[userId, pageId]}>
<Profile {userId} />
{#snippet failed(error, reset)}
<ErrorUI {error} {reset} />
{/snippet}
</FlareErrorBoundary>
Reports that know which component broke
A stack trace tells you which function threw. It won't tell you that the throw happened inside <Button>, which was rendered by <Modal>, which was rendered by <Layout>. That chain is usually the first thing you want to know, and it's exactly what stack frames lose once Svelte compiles your code.
To get it back, the package ships a Svelte preprocessor that registers each component as it initializes. Every report then includes the component name, its parent chain, and an origin classification:
{
"svelte": {
"componentName": "Button",
"componentHierarchy": ["Button", "Modal", "Layout"],
"errorOrigin": "event"
}
}
errorOrigin is one of render, event, effect, or unknown. A render error is a different kind of bug than one in a click handler or an async $effect, and now you can see which it was at a glance instead of working it out from the stack.
The preprocessor, and why it exists
In a production build, component names are gone. Svelte compiles them away. The preprocessor works around this by injecting a small registration call into each .svelte file at build time, so the component tree is there to read when an error fires.
Wire it up once in svelte.config.js:
import { withFlareConfig } from '@flareapp/svelte/config';
import adapter from '@sveltejs/adapter-node';
export default withFlareConfig({
kit: { adapter: adapter() },
});
withFlareConfig wraps your existing config and adds the preprocessor. If you'd rather be explicit, add it to the preprocess array yourself:
import { flarePreprocessor } from '@flareapp/svelte';
export default {
preprocess: [flarePreprocessor()],
kit: { adapter: adapter() },
};
It takes an exclude RegExp to skip files like vendored library code:
import { withFlareConfig } from '@flareapp/svelte/config';
export default withFlareConfig(
{ kit: { adapter: adapter() } },
{ exclude: /node_modules/ },
);
And a componentTracking flag to turn it off entirely:
export default withFlareConfig(
{ kit: { adapter: adapter() } },
{ componentTracking: false },
);
Leave it out and the boundary still works and still reports errors. You just fall back to component names pulled from stack frames, which are less reliable.
Hooks for shaping the report
The boundary exposes the same lifecycle hooks as the other Flare clients, so you can filter or add to a report before it leaves the browser:
<FlareErrorBoundary
beforeSubmit={({ error, context }) => {
return {
...context,
svelte: {
...context.svelte,
// attach your own data
},
};
}}
afterSubmit={({ error }) => console.log('reported', error.message)}
onReset={(error) => { /* user retried */ }}
>
<App />
{#snippet failed(error, reset)}
<ErrorUI {error} {reset} />
{/snippet}
</FlareErrorBoundary>
beforeEvaluate runs before solutions are evaluated, beforeSubmit lets you mutate or drop the context, afterSubmit fires once the report is sent, and onReset runs when the boundary clears.
Readable stack traces with sourcemaps
A production stack trace points at minified output, which is close to useless when you're trying to find the line that broke. SvelteKit builds with Vite, so you can drop in @flareapp/vite to upload sourcemaps on every build. Reports then show your original source instead of the compiled bundle.
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import flareSourcemaps from '@flareapp/vite';
export default defineConfig({
plugins: [
sveltekit(),
flareSourcemaps({ apiKey: 'YOUR_FLARE_API_KEY' }),
],
});
The plugin also injects your API key and a sourcemap version identifier into the build, so flare.light() picks them up with no extra wiring, just like the other client libraries.
Getting started
npm install @flareapp/svelte @flareapp/js
Needs Svelte 5.3 or newer. Add the preprocessor, wrap your app, call flare.light() with your project key, and you're reporting. Full setup is in the Svelte docs.
Running SvelteKit? There's also a SvelteKit package: @flareapp/sveltekit. It hooks into SvelteKit's error handling and attaches route context to every report.
Continue reading
New Webpack and Next.js plugins for Flare
We just shipped @flareapp/webpack and @flareapp/nextjs, two build plugins that upload sourcemaps to Flare after each production build. They replace the old @flareapp/flare-webpack-plugin-sourcemap package with webpack 5 support, automatic API key injection, and retry logic for flaky uploads. The Next.js wrapper also handles productionBrowserSourceMaps and sourcemap cleanup for you.
Dries
Copy-pasteable SQL in your Laravel query exceptions
Today we're shipping a small but lovely upgrade to Flare: every query exception now comes with a SQL statement you can actually copy and run.
Ruben
Subscribe to Backtrace, our quarterly Flare newsletter
No spam, just news & product updates