I’ve been building web applications for years, and I keep hitting the same wall. My UI is snappy, my logic is clean, but the moment I need to talk to a server—to fetch a user’s profile, load a product list, or submit a form—everything gets messy. Loading spinners, error messages, caching logic, and stale data updates end up scattered throughout my code. It feels like I’m writing the same complex plumbing over and over again. Recently, I found a combination that has fundamentally changed how I handle this problem. Let’s talk about bringing together the raw speed of Solid.js with the intelligent data management of TanStack Query.
Solid.js caught my attention because it works differently. Instead of comparing a virtual copy of the DOM to find changes, it knows exactly which parts of your UI depend on which pieces of data. When the data changes, it updates only those specific parts. The result is incredible speed with very little effort from me. But Solid is brilliant at managing state that lives in the browser. For data that lives on a server—your user data, blog posts, shopping cart—you need a different kind of tool.
This is where TanStack Query comes in. Think of it as a smart assistant for your server data. You tell it where to get the data, and it handles everything else: showing a loading state, caching the response, updating the cache in the background when data might be old, and even retrying failed requests. It manages the entire lifecycle of that remote information so you don’t have to. The magic happens when you let Solid manage your reactive UI and let TanStack Query manage your server state. They each focus on what they do best.
Setting this up is straightforward. First, you wrap your application with TanStack Query’s provider, giving it a client that controls the cache. In Solid, this usually happens in your main index.jsx or App.jsx file.
import { render } from 'solid-js/web';
import { QueryClient, QueryClientProvider } from '@tanstack/solid-query';
import App from './App';
const queryClient = new QueryClient();
render(() => (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
), document.getElementById('root'));
With the provider in place, you can start fetching data inside any component. The createQuery hook is your main tool. You give it a unique key and a function that fetches the data. TanStack Query does the rest. Here’s how you might fetch a list of projects.
import { createQuery } from '@tanstack/solid-query';
function ProjectList() {
const projectsQuery = createQuery(() => ({
queryKey: ['projects'],
queryFn: () => fetch('/api/projects').then(res => res.json())
}));
if (projectsQuery.isLoading) return <div>Loading projects...</div>;
if (projectsQuery.isError) return <div>Error: {projectsQuery.error.message}</div>;
return (
<ul>
{projectsQuery.data.map(project => (
<li>{project.name}</li>
))}
</ul>
);
}
See how clean that is? The component declares what data it needs. The hook provides the data, along with the current status. Solid then reacts to changes in that status or data and updates the DOM precisely. What happens when the user adds a new project, though? You don’t want them to see an outdated list.
This is where mutations come in. After creating a new item on the server, you need to update the local cache. TanStack Query’s createMutation hook makes this predictable. You can easily tell it to refetch the ‘projects’ list after a successful mutation, ensuring the UI shows the latest data.
import { createMutation, useQueryClient } from '@tanstack/solid-query';
function AddProjectForm() {
const queryClient = useQueryClient();
const mutation = createMutation(() => ({
mutationFn: (newProject) => fetch('/api/projects', {
method: 'POST',
body: JSON.stringify(newProject)
}),
onSuccess: () => {
// Invalidate the 'projects' query to trigger a refetch
queryClient.invalidateQueries({ queryKey: ['projects'] });
}
}));
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
mutation.mutate({ name: formData.get('projectName') });
};
return (
<form onSubmit={handleSubmit}>
<input name="projectName" type="text" />
<button type="submit" disabled={mutation.isPending}>
{mutation.isPending ? 'Adding...' : 'Add Project'}
</button>
</form>
);
}
The beauty of this setup is in the synergy. When invalidateQueries is called, TanStack Query marks that data as stale and refetches it in the background. Once the new data arrives, the projectsQuery.data signal in our ProjectList component updates. Solid.js sees this change and surgically updates only the list items in the DOM that are affected. There’s no large component re-render, just a minimal, efficient DOM update. Have you ever noticed a list updating seamlessly in an app and wondered how they did it? This is often how.
The benefits are huge for user experience. Imagine a dashboard with many independent widgets fetching data. With this pattern, each widget manages its own data lifecycle. One widget can refetch in the background without causing jank or loading spinners in unrelated parts of the screen. The app feels alive and responsive because updates are granular and efficient.
For me, this combination has become the foundation for any data-driven Solid.js application. It removes a massive layer of complexity and lets me focus on building features instead of managing state. The code is simpler to write, easier to reason about, and results in a faster experience for the person using it. It turns a tangled problem into a straightforward solution.
If you’re tired of wiring up data fetches by hand and want your apps to feel instantly responsive, I strongly suggest trying this stack. It might just change your workflow as much as it changed mine. What part of your current project could benefit from smarter, automatic data handling? Let me know in the comments—I’d love to hear what you build. If you found this helpful, please share it with another developer who might be wrestling with the same challenges.
As a best-selling author, I invite you to explore my books on Amazon. Don’t forget to follow me on Medium and show your support. Thank you! Your support means the world!
101 Books
101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.
Check out our book Golang Clean Code available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!
📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!
Our Creations
Be sure to check out our creations:
Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools
We are on Medium
Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva