With this experiment, we are making a significant change in the way you think about, and build Redwood apps. Redwood now becomes SSR-first, and moves away from the Jamstack model of deploying static web assets to a CDN. Your routes are streamed from the server, then hydrated on the client — leveraging React 18’s new streaming & Suspense capabilities.
Part 1: Let’s start rendering on the server + dynamic <meta> tags for SEO and link sharing
What you’ll be able to do
Dev, with streaming + SSR Build, then deploy a prod server Dynamically generate HTML <meta> headers, so that when you share your links on Discord/Twitter/Slack - you can generate link previews
Make sure you’re on the canary version of Redwood (v7.x-canary)
yarn rw upgrade -t canary
And now, let’s setup your project for streaming!
yarn rw exp setup-streaming-ssr
This will create a few files:
(overwrite) web/src/entry.client.tsx
web/src/entry.server.tsx
web/src/components/Document.tsx
Note that this now becomes your “index.html”. So if you have any customisations there, you might want to bring them in here.
While SSR-Streaming is experimental, please don’t remove the index.html file in web/src/index.html - as this is still required.
It will also add a flag to your redwood.toml that’ll tell Redwood internally that we need to build and run your project differently.
Tada, that’s it!
Now when you:
Run yarn rw dev — it will server-render your pages
If you want to run a built version:
yarn rw build process will build your project ready for server rendering
yarn rw serve will run a web server (along with your usual api server)
You can use the meta route hooks (see section below)
This is where you start to see more benefits of server rendering+streaming, as we make use of React 18’s Suspense architecture, allowing you to “render-as-you-fetch”. This is very alpha and the steps are likely to change.
What you’ll get Cells Rendering on the server Ability to set dynamic meta tags using MetaTags component (in addition to route hooks) - off the back of a Cell query Stream results in of your Cell, as they’re resolved i.e. render-as-you-fetch. If you have multiple Cells (or indeed if you directly use useSuspenseQuery or useReadQuery) - your pages should feel significantly faster on the first render.
Assuming you’ve setup up part 1 already, there’s 3 more steps:
Swap your ApolloProvider
in your web/src/App.tsx let’s swap where the ApolloProvider is imported from
This will enable your Cells to render under Suspense.
Now let’s install the experimental apollo client that we need for streaming and ssr
Although it says “NextJS” - the specific version is an experimental build specific to Redwood while we work out all the details with the Apollo team
yarn workspace web add @apollo/experimental-nextjs-app-support@0.0.0-commit-5141fa5
Note the version number 0.0.0-commit-5141fa5 is important!
Et voila. You’ve succesfully enabled streaming+ssr capabilities for your Cells!
Some Gotchas!
If you are using queryResult in your Cells, you may notice API changes here. This is still in flux, and changing day-to-day: regardless, please let me know if you were expecting APIs here that you can’t implement any other way
Auth currently does not work with server side rendering, however your app will automatically revert to client side rendering, if any queries fail to render on the server
Under the hood, Cells now fetch with useBackgroundQuery and useReadQuery - this enables Suspense and “render-as-you-fetch” - but it does change how you reason about some of the lifecycle.
A good example of how there are subtle differences are explained in this section: https://www.apollographql.com/docs/react/data/suspense#refetching-and-pagination where refetching will cause the Loading component to show. This is the same in Redwood, and if you wanted to not show loading (or fade out old results), you can use React’s useTransition hook to wrap your refetch.
What’s next?
I’ll post some videos next week or so, showing some of the cool things you can achieve with Suspense enabled cells, and streaming them!
Thanks for all your work on this. I’m about to start another a new redwood project. Would you take the the leap and use SSR or play it safe and stick with old school RW for now?
Thanks for all your work on this. I’m about to start another a new redwood project. Would you take the the leap and use SSR or play it safe and stick with old school RW for now?
Hi Shan, it depends on what your appetite for dealing with changes are. While SSR+Streaming is in the experimental stage, we will make changes under hood and we cannot guarantee that function signatures, etc. won’t change - it won’t be part of semantic versioning, so sometimes we will break things even in minor versions/patches.
That being said, all you have to do to switch the experimental.streamingSsr flag in your redwood.toml, and switch the Apollo provider to toggle between stable and experimental.
We are grateful for any feedback in the experimental stage, and it would be your chance to shape these features (and call out missing ones) - so when this does become stable, you’ll be among the first to ship with these benefits without needing to adjust your code!