Introducing Solid.js and SolidStart
Solid is starting to get more interesting than ever. The new Solid Start Beta is super promising. If you're not already familiar, Solid is a React alternative focused on signals that is really, really performant. React alternative might be a controversial way to describe a framework, but Solid is by far the most I felt like my mental model from React could carry over. I have found Solid to be a really pleasant experience with its own set of mind-blowing ways to write things that are really cool.
The Evolution of SolidStart to Beta 2
Overall Solid Start is more like Next.js where it's a full stack solution for building SolidJS applications where the back end, the bundling and all of the things around it are being managed for you. It seems like we have more and more of these full stack Frameworks every day, but I want to be very clear that Solid Start was early. It's not like as early as Remix, but it was earlier than a lot of the stuff that we talk about now, and it's also evolved a ton over time.
Initially Solid Start was built around Vite with its own handling of the server side stuff, because at the time Vite didn't really have a happy path for servers. Vite was focused on building client bundles. While this was going on, there were two other groups really invested in better full stack and server side experiences in Vite. Those two groups were Astro and Nuxt, both building backend-first full stack solutions on top of Vite. Over time, a lot of us started to centralize on Astro as like a happy path starting point, and we started to see work both in Solid Start and outside of it to try and make frameworks built around Astro as the primitive. The effort that was put into these frameworks around Astro was huge and both helped Astro and the Vite community grow immensely, but it didn't help Solid Start much. It ended up spending a good bit of time both soul searching and trying to figure out how to make a better more maintainable experience over time.
Thankfully, a huge development has happened over the last year. That development is Nitro, a project built around Vite to power both Nuxt and other frameworks trying to do full stack within Vite. Think of it as the starting point if you wanted to build your own Next.js or in this case Solid Start. And not only did Solid embrace this, they actually rebuilt the majority of the framework from Beta 1 to Beta 2, which is why this is such an interesting release.
Ryan Carniato's Transparent Announcement
So without further ado, let's dig into what Ryan and team changed with the newest version of Solid Start. This is a message from Ryan, the creator of Solid and Solid Start, and I love how real he's being with this. Most posts about an update are focused on a bullet point list of new features. Ryan's actually starting a conversation. This is a post in their discussions in the announcement section and I really like how real it feels.
It's been a lot of anticipation about when Solid Start can get out of beta and move to 1.0. Unfortunately, we are not ready yet. I think this is clear from the nature of the bugs and issues we are facing. While there are some happy paths like Node, Unify, and SSR, a lot of what Solid Start does is pretty buggy. They've also learned a bunch about the APIs, both what's worked and what's failed, and they want to design a platform that keeps them open for the future.
"I apologize for the time it has taken to post another update." That's a really cool thing to open an announcement like this with, to be real that this has taken too long and explain what thinking is and where we've been in that time. The last one was over 8 months ago. Even then, the path for what we needed to do was clear, it just wasn't obvious how to achieve it. There were some fundamental issues with how Start was set up and a large amount of work was required to fix it. We've done a lot of exploration over the last several months that now I feel comfortable starting to discuss Start's future, and that starts with Beta 2, a second Beta run that applies what we've learned.
Why market like so? Well, there have been some breaking changes, not necessarily the largest for hobby apps, but we want to change how Solid Start deploys. We also need to make some other API level changes which is why I want to include everyone in the discussion. Some decisions are pretty certain but may have a lot of details that are still being worked out that could use your feedback. So here's a summary of the changes.
The Core Rebase: Nitro and Vincy
The big one is rebasing to Nitro adapters in Vincy. As I mentioned before, Nitro is the new starting point for full-stack frameworks built around Vite, and they've done a great job integrating it. It also powers Analog, which is the full-stack Angular framework made by Brandon Roberts, which is actually really cool if you're actually into Angular. Analog's increasingly the cool way to do it. And also obviously Nuxt, which is huge.
I'm personally not as familiar with Vincy, JavaScript server toolkit to build full-stack apps and frameworks with your own opinions powered by Vite and Nitro. So this seems like the backend side and a lot of the compiler stuff. I also know it was really inspired by Bun's app bundler stuff, which is really cool. It's Vincy is how it's pronounced. Cool, thank you for the correction, appreciate that a ton. So Vincy is again an abstracted building block for making good full-stack solutions. And if I recall, they were able to significantly clean up the code due to moving to these parts. And with this, they also get access to a lot of the Vite plugin ecosystem. So support for things like per-page pre-renders and properly supported client-side only is actually viable now.
This what I probably should have opened earlier, this is the actual release notes for Solid Start Beta 2. "Been a long year, we couldn't be more thrilled to see all the amazing projects built on Solid Start." Things like Post.news being built on Start, amongst others. Had incredible support from companies and contributors including Chrome's team helping in their research for performance increasing tech. Really cool stuff.
However, we've learned a lot in this year both in terms of our technology approach and the efforts to maintain a meta framework. What we had done worked, but it didn't work well and it became apparent early in the year we need to do something about it. And that itself was a journey into exploring different technologies. In the end, they settled on Nitro to provide our server layer for Start. As I mentioned before, Nitro and Vincy are the new core for Solid Start, so they no longer have to write a lot of that code themselves. And the result is that Solid Start went from 10,000 lines of code to 1,400, and 32 files instead of 150. That's a massive win. That's not just like a win because oh, you have less code, it's going to run better. That's a win because you have less overhead to think about when you make decisions and changes. Working in this code base is now more than 10 times easier if there's less than 10 times the amount of code. That's a huge win and I'm excited to see how much faster Solid Start can move as a team and a product they're iterating on now that there's so much less they have to deal with as they do it. Huge shout out to all the people who made it possible for this release to happen.
A Router-Agnostic Architecture
First we need to talk about that rebase. By rebasing to Nitro and the Vincy adapters, they have changed how starting things works and also given you the ability to configure any of the settings that Nitro gives you access to, which is cool because that's an open standard with its own plugin architecture and ecosystem that you can adopt here without having to make Solid-specific stuff. This means full access to pre-rendering in any project, including automated link crawling, dozens of built-in presets for deployment, the full power of H3 which is a universal HTTP server, as well as cozy integration with the rest of the NuxtJS ecosystem. Really cool stuff and I'm hyped to see how much progress it's made.
They also went router and metadata agnostic. Instead of the router being a deeply integrated part of Solid Start, it's now a package that has good hooks to integrate into the framework. This abstraction both means that the router can iterate and improve separately from the framework, but also that other routers can be introduced as well. Really interesting to see the split, not many frameworks have so boldly split the router from the framework. In fact, React's kind of going the opposite way where the router and the framework are more and more becoming one thing, but it is nice to see Solid try to separate these out and see the result that we get.
And the file system routing is consumable by any router. So if you're using the file system routing in solid, you can have a different router that actually works with the result of it. Really interesting stuff. So like we're importing router from solid-router, we're still mounting this route, still rendering things that way. We also grab the file routes from Solid Start, and then make those a child of the router. That's really interesting. And the page entry support a route config too, so in a given route you can export a config and that will be used by the page. Yeah, cool stuff. Feels a lot like create-react-app or Vite app, except it works as SSR and deployment out of the box. Cool stuff.
Adopting React's use server Convention
Here's where things get interesting. We've talked a lot about use server on the channel. I haven't talked about use server outside of React. I remember when use server and use client were first introduced seeing Ryan realize that these are compiler-level things that other frameworks can use. use server and use client, despite being built for React and React use cases, are pretty generic bundler behaviors that you can use for other frameworks. And as such, they introduced server functions through the same primitive, use server. Theirs have a few differences, specifically you can't inline them the same way you do with React server components and server actions. So if you want to have a delete button inside of your component, you have to bind values to it rather than having them inferred through closure automatically. Really interesting stuff. I watched a little bit of Ryan showcasing this in his last stream. I'll make sure we link a timestamp to that in the description if you want to see more of how he's doing it.
But let's read about why. server$ was a pretty powerful convention for server functions. If you're not already familiar, in the previous Solid Start version, in a client file you could write server$ and then write a function inside of there and that would then become effectively an RPC call that you could call wherever you wanted. Really, really cool stuff, but it also meant you were writing server code in your client files, which not everyone wants to do, and for good reason. Ideally your server files that have server-only code would exist elsewhere and you can import from them, but server$ intermingled things in a less clear way. And it was cool cause like you could handle type safety and things like that well, but it was weirdly co-mingled and collocated.
But that's why with Solid Start Beta 2, they've picked up the React convention to move to use server. It has other advantages of allowing for module-level scope, making it more visually clear that a server function is different, and it's consistent with React's ecosystem, which will make it easier for us to leverage work from other bundlers in a way that's similar to our choice to use JSX with Solid. There are some key differences though. Here, I was talking about this a little bit. Their server functions are just functions, so if you want server actions, those are usually just calling server functions and then wrapping them with the Solid Router's action primitive. In Solid, the idea of an action and the idea of a server function are different, where an action's a router concern and a server function's a thing the server is doing when you call it. I think it's a good call to separate these because you might have actions that don't necessarily hit the server, you might have server functions that don't necessarily need to be an action. So this is a good separation. I'm curious how people will feel about that over time.
They also call out that their server functions are RPC in the browser but just plain function calls on the server. They can be called on the server or on the client as needed. Again, really cool stuff. Our server functions exist independently of the concept of server components. They can be declared anywhere. They do not do closure extraction, so you can only close over variables at a module scope. They will not automatically grab server code and serialize it in the client. Again, it's one of the weird things that server actions in Next and React do that they've chosen not to do. The result is that the code's slightly less ergonomic and feels a little less like traditional JavaScript, but none of those weird edge cases and unexpected behaviors exist as a result. It's much clearer what it's doing when you do it.
He even says that the benefit of this approach is that server functions will work with any existing promised library, whether built-in primitives like createResource or third parties like createQuery from TanStack Query. So even though it feels a little less like JavaScript, it behaves much more like it and will behave with these other tools much better.
Advanced Serialization with Seroval
Our server functions also got a serious shot in the arm using Solid's serializer, Seroval, to handle the encoding, letting us stream back a variety of data formats. I haven't actually looked at Seroval, hope I'm pronouncing that right. Of course, good old Alexis killing it. There's a way to serialize objects of all sorts of different shapes by the looks of it. Cool stuff. I will be starring that. Looks very interesting. Sending promises or even async iterators over the wire. Interesting, very interesting.
Enhanced Support for Client-Side Apps
And point four, client-rendered single page apps are still very real. We're serious about supporting existing applications. Sometimes a move to server rendering isn't easy. Luckily you can just toggle ssr: false in your config. But it's more than that. Just because you have a client-rendered SPA doesn't mean you shouldn't be able to benefit from easy APIs with server functions. Client-rendered only apps can still use server functions. Really cool stuff. So you have a client application that just so happens to call server functions. Really interesting.
When you make the decision to do server rendering, beyond just flicking the switch, we provide a client:only wrapper that allows you to define code that can't run on the server to be lazily loaded in the client and run after hydration. Things like jQuery plugins or big browser-only data grids can now work seamlessly with SSR. This is not too different from the Next lazy import where you specify ssr: false. It's nice that there's an actual client:only name, and I do hope that Next copies this because it's really nice to have a thing called client only. It's very clear, very nice. But this is a behavior that exists in other solutions.
The Road to 1.0 and Other Features
And everything else. Bunch of other new features, but that doesn't belong here, respective library. So that's the point. Solid Router has async cache and action stuff. They also have added createRouteData and createServerData API, better TypeScript support. The Meta, which is the metadata library, now has zero-configuration SSR head injection for putting the right title in the right place at the right time. Solid Router, you can also use the old version of solid-router in the new Solid Start. That's really interesting.
What you have here are the primitives you need from a meta framework: file system routing, advanced bundling for things like server functions and islands, and a universal server runtime and deployment system. And again, he apologized for how long it took. They're still on the road to 1.0. By rebuilding the foundation and stabilizing things, we're on a much happier path than we were to actually get to 1.0. There are pieces to iron out from TypeScript to tests to bug stomps to deployment bundling issues, but they're working hard on getting there and I'm really excited to see it.
Final Thoughts: Why Solid Is Exciting
I am genuinely really hyped about all the work the Solid team has done. As I've said many a time before, it's the most exciting framework outside of React for me, and I hope this helps you see why. They're learning all of the right things from React while also challenging the way that they've been presented and architected so that we can have a lot of those wins without having a lot of the potential negatives.
I'm hyped that React's being challenged in such a meaningful and exciting way, and I will continue keeping a close eye on all the stuff going on in the Solid community. What do you think? Is it the time that I start using Solid Start for my content instead of Next.js, or should I go use Svelte instead? What framework has you most excited now? If you want to watch me compare all these different frameworks, I'll pin a video in the corner where I do that. Thank you guys as always, see you in the next one. Peace nerds.