I've debugged SolidJS apps at 2AM more times than I care to admit. While everyone debates SolidJS 2.0, the real world runs on 1.x - and that's where the production disasters happen. Here are the clusterfucks that actually break in production and the fixes that work when Stack Overflow has zero answers.
Hydration Mismatch: The Silent Production Killer
Error: Hydration Mismatch. Unable to find DOM nodes for hydration key: someKey
This shit breaks silently in production but works fine locally. I've spent 6 hours debugging this exact error on a dashboard that worked perfectly in dev.
What causes it:
- Date/time rendering different on server vs client
- Random IDs or Math.random() in your components
- Async data that resolves differently between server and client
- Nested ternaries with complex objects
The nuclear fix that actually works:
// If you're using Date.now() or Math.random() in render, stop
// This breaks hydration every damn time
function BrokenComponent() {
return <div id={Math.random()}>Content</div>; // Never do this
}
// Use stable IDs instead
function FixedComponent() {
return <div id=\"stable-id\">Content</div>;
}
For async data hydration mismatch:
// This breaks because server and client finish at different times
const [data] = createResource(() => fetchUserData());
// This works - serialize the data correctly
const [data] = createResource(() => fetchUserData(), {
initialValue: () => serverData // Pass server state to avoid mismatch
});
First thing to check: Are you using Date.now()
, Math.random()
, or any time-based values in your JSX? Remove them.
Memory Leaks: When Your Fast App Becomes Slow as Shit
SolidJS is supposed to be memory efficient, but you can still fuck it up. I found a 200MB memory leak in our dashboard that brought Chrome to its knees after 30 minutes of use. Use Chrome DevTools Memory tab to track these issues.
Common SolidJS memory leak sources:
1. Event listeners that don't clean up:
// This leaks - event listener never gets removed
function LeakyComponent() {
const [count, setCount] = createSignal(0);
document.addEventListener('keydown', () => {
setCount(c => c + 1);
});
return <div>{count()}</div>;
}
// This works - cleanup in onCleanup
function FixedComponent() {
const [count, setCount] = createSignal(0);
const handler = () => setCount(c => c + 1);
document.addEventListener('keydown', handler);
onCleanup(() => {
document.removeEventListener('keydown', handler);
});
return <div>{count()}</div>;
}
2. Uncanceled resources:
// This can leak if component unmounts during fetch
const [user] = createResource(userId, fetchUser);
// Add error handling and cancellation
const [user] = createResource(userId, async (id, info) => {
const controller = new AbortController();
info.refetching && controller.abort(); // Cancel previous requests
try {
return await fetchUser(id, { signal: controller.signal });
} catch (error) {
if (error.name !== 'AbortError') throw error;
}
});
3. Infinite createEffect loops:
// This creates infinite loops and memory issues
const [data, setData] = createSignal({});
const [processed, setProcessed] = createSignal({});
createEffect(() => {
const newData = processData(data());
setProcessed(newData);
setData(newData); // This triggers the effect again - infinite loop
});
// Fix with proper dependency management
createEffect(() => {
const result = processData(data());
setProcessed(result);
}); // Don't update data inside the effect
Debug memory leaks:
- Chrome DevTools → Memory tab → Take heap snapshot
- Look for objects growing between snapshots (memory profiling guide)
- Search for your component names in retained objects
- Check if onCleanup functions are actually running
Performance Hell: When SolidJS Isn't Fast Enough
SolidJS is fast, but you can still make it slow. Here's how I found and fixed performance issues that made our real-time dashboard stutter. Use Chrome DevTools Performance tab to identify bottlenecks.
1. Massive signal updates:
// This kills performance - 1000 signals updating
const [items, setItems] = createSignal([]);
// Every item change triggers re-render of entire list
for (let i = 0; i < 1000; i++) {
const [item, setItem] = createSignal(data[i]);
items.push(item);
}
// Use stores for collections instead
const [items, setItems] = createStore([]);
// Update just one item - rest stay unchanged
setItems(index, 'property', newValue);
2. Expensive computations in render:
// This recalculates on every render
function ExpensiveComponent(props) {
const expensiveResult = heavyCalculation(props.data); // Bad
return <div>{expensiveResult}</div>;
}
// Cache with createMemo
function FastComponent(props) {
const expensiveResult = createMemo(() => heavyCalculation(props.data));
return <div>{expensiveResult()}</div>;
}
3. DOM thrashing with large lists:
// Don't render 10,000 DOM nodes
{items().map(item => <ItemComponent item={item} />)}
// Use virtual scrolling for large lists ([TanStack Virtual docs](https://tanstack.com/virtual/latest))
import { createVirtualizer } from '@tanstack/virtual-core';
const virtualizer = createVirtualizer({
count: items().length,
getScrollElement: () => parentRef,
estimateSize: () => 35,
});
Hot Reload Death: When Dev Server Becomes Useless
Hot reload breaks daily in SolidJS. Here's how to fix it without losing your state. Check Vite HMR troubleshooting for common issues:
When hot reload dies completely:
## Nuclear option - deletes all Vite cache
rm -rf node_modules/.vite
rm -rf node_modules/.cache
npm run dev
When specific files won't hot reload:
// Large components break HMR - split them up
// This 500-line component kills hot reload
function MassiveComponent() { /* 500 lines */ }
// Split into smaller components
function HeaderSection() { /* 50 lines */ }
function BodySection() { /* 100 lines */ }
function FooterSection() { /* 50 lines */ }
Hot reload debugging tricks:
- Check browser console for HMR errors
- Look for circular imports (these break HMR)
- Remove default exports temporarily (named exports reload better)
- Check if you're importing CSS files in weird ways
SSR Failures: When Your Server-Side App Dies
Error: ReferenceError: document is not defined
or window is not defined
This happens when browser-specific code runs on the server. I've seen this break entire deployments.
Common culprits:
// This breaks SSR - no localStorage on server
const [theme, setTheme] = createSignal(localStorage.getItem('theme'));
// Fix with isServer check
const [theme, setTheme] = createSignal(isServer ? 'light' : localStorage.getItem('theme') || 'light');
// Or use clientOnly
function ThemeComponent() {
return (
<clientOnly>
{() => {
const savedTheme = localStorage.getItem('theme');
return <div>Theme: {savedTheme}</div>;
}}
</clientOnly>
);
}
Window/document access:
// Breaks on server
window.addEventListener('resize', handler);
// Fix with createEffect + isServer
createEffect(() => {
if (isServer) return;
window.addEventListener('resize', handler);
onCleanup(() => window.removeEventListener('resize', handler));
});
Debugging Tools That Actually Help
1. Solid DevTools Chrome Extension
- Install from Chrome Web Store
- Shows reactivity graph and signal values
- Requires
@solid-devtools/debugger
package in dev
npm install -D @solid-devtools/debugger
2. Chrome DevTools Performance Tab
- Profile component render times
- Find expensive signal updates
- Identify memory leaks over time
3. Console debugging that works:
// Debug signal updates
const [count, setCount] = createSignal(0);
console.log('Count changed:', count()); // Won't work - doesn't track
// Track signal changes properly
createEffect(() => {
console.log('Count is now:', count()); // Logs on every change
});
// Debug computations
const doubled = createMemo(() => {
const result = count() * 2;
console.log('Doubled computed:', result);
return result;
});
The 3AM Debugging Checklist
When everything is fucked and you need to debug fast:
- Check hydration: Look for
Date.now()
,Math.random()
, time-based rendering - Check memory: Take heap snapshots, look for growing objects
- Check infinite loops: Search for signals that update themselves in effects
- Check SSR: Look for browser APIs used during server render
- Check hot reload: Clear Vite cache, restart dev server
- Check console: SolidJS logs are better than you think
- Check network: Failed API calls cause weird component behavior
Nuclear debugging command:
rm -rf node_modules/.vite && rm -rf dist && npm install && npm run dev
This fixes 70% of weird SolidJS issues. When in doubt, nuke the cache.