Mixing React and SolidJS in One App
The Framework Dilemma
Every project starts with a framework choice: React, SolidJS, Vue, Svelte? Each has strengths, and the “right” answer depends on what you’re building. But what if you didn’t have to choose just one?
Astro makes this possible. In Multron, we use React for complex stateful UIs like the conversations page, and SolidJS for lightweight interactive components like the sign-in form — all within the same application.
How It Works
Astro treats each interactive component as an independent island. When you add a client:* directive, Astro hydrates that component with its framework runtime — but only that component. The rest of the page remains static HTML.
Here’s an Astro page that renders both a React and a SolidJS component:
---
import BillingForm from '../components/react/BillingForm'
import AuthStatus from '../components/solid/AuthStatus'
---
<AuthStatus client:load />
<BillingForm client:load />
Each component hydrates independently. The React runtime loads for BillingForm, and the SolidJS runtime loads for AuthStatus. They share no framework code — and that’s the point.
Directory-Based Framework Separation
Since both React and SolidJS use .tsx files, Astro needs to know which compiler to use. Multron solves this with directory-based routing:
// astro.config.mjs
integrations: [
react({ include: ['**/react/**'] }),
solidJs({ include: ['**/solid/**'] }),
]
Any .tsx file under a react/ directory gets compiled with React’s JSX transform. Files under solid/ use SolidJS. This is simple, explicit, and impossible to get wrong.
Bundle Efficiency
A common concern with multi-framework setups is bundle size. Astro handles this well:
- Framework runtimes are loaded once per page, regardless of how many islands use that framework
- Islands hydrate independently — a slow-loading React island doesn’t block a SolidJS island
- Pages without islands ship zero JavaScript — like this blog post
If a page only uses SolidJS islands, React’s runtime never loads. If a page has no islands at all, no framework JavaScript is sent to the browser.
When to Use Which
In Multron, we follow a simple heuristic:
| Use Case | Framework | Reason |
|---|---|---|
| Complex forms with rich state | React | Mature ecosystem, React Hook Form, etc. |
| Simple interactive widgets | SolidJS | Smaller runtime, fine-grained reactivity |
| Content pages | None (Astro) | Zero JS, maximum performance |
| Data-heavy dashboards | React | Component libraries, React Query |
The key insight is that this isn’t an either/or decision. You pick the best tool for each piece of your UI, and Astro handles the integration.
State Sharing Across Frameworks
When React and SolidJS islands need to share state (e.g., authentication status), Nano Stores provides a framework-agnostic solution at under 1 KB. Both @nanostores/react and @nanostores/solid offer hooks that subscribe to the same underlying store.
Read more about this pattern in why multiple frameworks.