Well, the answer is simple: You can build a SPA with Astro next to your static and server-rendered pages. This way, you can have the best of both worlds: a fast and SEO-friendly website for your marketing pages, and an SPA for your interactive application.
At the same time, you can also use Astro to build your backend API. This way, you can build your entire application with Astro, without having to use any other framework or tool.
From there, you can do all sorts of things: bring in tRPC and React Query to handle the client-server communication, re-use your React components on the server side, and much more.
Setting up Astro
To get started, let's create a new Astro project and add React and the Node.js adapter:
Change into the newly created directory and install React and the Node.js adapter:
Next, install React Router:
With that done, we can start building our application.
Building our Single Page Application (SPA)
Let's start by creating a new file called
src/components/app.tsx and create a very simple React application using React Router.
First, let's create a few pages:
Next, let's create a simple nav bar using React Router's
Then, let's create a simple layout component that renders the navbar and the current page:
Finally, let's define our router using
createBrowserRouter and render our application:
With that done, we now have a very simple React application with three pages and a navigation bar. Let's now move on to the Astro part.
Adding a route for our SPA
To add a route for our SPA, we need to create a new file and render our React app just like we would do with any other React component when using Astro. The only difference is that we need to make sure we set up a catch-all route so that all requests are handled by our SPA.
To do that, let's create a new file called
src/pages/dashboard/[...all].astro. This will create a new route for our SPA that matches all routes starting with
/dashboard. You can, of course, change this to whatever you want.
Next, we want to import our Astro's Layout component and render our React app inside of it:
Note that we're passing
client:only to our React app. This is because we don't want to render our React app on the server side. Instead, we want to render it on the client side only.
Now that we have our SPA route set up, we can run our application and see it in action:
Head over to
http://localhost:4321 and you should see your Astro application. If you navigate to
http://localhost:4321/dashboard, you should see your React application and be able to navigate between the different pages.
As you can see, it's very easy to build an SPA with Astro. All we did was create a catch-all route in our Astro application and let it render our React application. You can do the same with any other framework or library, such as Vue, Svelte, or Solid.
From there, what I like to do is use tRPC and React Query to handle data fetching and client-server communication. This way, you get type-safe communication between your client and server, and you could still use the same tRPC endpoints on the server side to fetch data for your static pages.
This setup works well for small to medium-sized applications and provides a great developer experience and performance without having to use a monorepo or any other complex setup.
If you're interested in learning more about Astro, I've written a few other articles on things such as implementing Incremental Static Regeneration (ISR) with Astro and setting up Astro with SQLite and Litestream.
Until next time, happy coding!
Interested in LogSnag?