I recently got asked how to move from RSC in the Next App Router to SolidStart so figured I’d document how I think of things.
Now first a disclaimer, SolidStart allows you to get data from the server like RSC but it is still pretty different than Server Components. SolidStart may explore server components in the future, but right now it has a bit more of a client centric approach.
Getting data from server
To fetch data in RSC it looks something like this:
export async function Polls() {
const user = await getUser();
const polls = await getPolls();
}
async function getUser() {
// get user from db
}
async function getPolls() {
// get list of polls from db
}
In Next components are by default server components that only run on the server so awaiting server data like this just works.
Now in SolidStart components are isomorphic and run on the client and server so things have to change a bit. Let’s look at some code and then compare the differences.
export function Polls() {
const user = createAsync(() => getUser());
const polls = createAsync(() => getPolls());
}
async function getUser() {
"use server";
// get user from db
}
async function getPolls() {
"use server";
// get list of polls from db
}
Component is not marked async
SolidStart does not have async components, so you can’t use the await
syntax and instead use createAsync
. This is actually beneficial because the await
syntax causes waterfalls. We can’t get the polls until after we’ve got the user.
In the SolidStart version the async primitive is non-blocking and thus can render everything out using our suspense boundaries and stream in our data independently.
Async functions have “use server”
So if you noticed on the RSC version we didn’t need the "use server"
directive. This is because these functions were automatically server only. Remember in the case of SolidStart the components are isomorphic and run on the server during SSR, and hydrate on the client.
Because of this we need to define a boundary stating these should be exposed to the frontend and called by the client via an RPC call. On the flip side they are just regular functions on the server during SSR.
If your coming from React this is a bit confusing because "use server"
is reserved for server actions and mutating data. SolidStart repurposes this into a more generic server function primitive that can also be used to fetch data.
Conclusion
I think server functions are a great primitive that allows you to get server data without having to fundamentally change your mental model.
Now there is a bit more ceremony to setup, but I think it’s almost more explicit which is on the server versus the client.
I hope you’ve found this useful!