12k
All articles

Server-Rendering in Solid mit SolidStart

Erstellen Sie eine SolidStart-v2-App mit serverseitig gerenderten Daten, query und createAsync, Route-Preloading, Serverfunktionen und Deployment.

OpenReplay Team
OpenReplay Team
Server-Rendering in Solid mit SolidStart

SolidStart v2 (@solidjs/start 2.x) · Solid v1 · Node.js 24+ · Vite 8

SolidStart ist das Full-Stack-Framework für SolidJS. Es ergänzt Solid-Komponenten um dateibasiertes Routing, Server-Rendering und Server Functions und übernimmt damit die Rolle, die Next.js für React und SvelteKit für Svelte spielt.

Wenn Sie bereits Solid-Komponenten schreiben, sind beim Umstieg auf Full-Stack vor allem die Tutorials das Problem. Die meisten verwenden noch app.config.ts und Vinxi, und beides gibt es in der aktuellen Major-Version nicht mehr. Dieser Artikel baut eine kleine SolidStart-v2-App mit serverseitig geladenen Daten und einer Detailseite mit Preloading. Anschließend geht es um Server Functions, die Rendering-Konfiguration, das Deployment und die Frage, ob das Ökosystem reif genug ist, um es einem React-Stack vorzuziehen. Vorausgesetzt werden die Muster auf Komponentenebene, die in SolidJS Best Practices behandelt werden.

Das Wichtigste in Kürze

  • SolidStart v2 ist seit dem 4. August 2026 stabil. Es zielt auf Solid v1 ab, ersetzt Vinxi durch die Environment API von Vite, setzt Node.js 24+ und Vite 8 voraus und wird in vite.config.ts konfiguriert.
  • Routendaten werden in SolidStart v2 geladen, indem man eine asynchrone Funktion in query aus @solidjs/router einschließt und sie mit createAsync ausliest.
  • Eine "use server"-Direktive am Anfang eines Query-Bodys sorgt dafür, dass die Funktion auf dem Server läuft, wo sie auf Secrets und Session-Daten zugreifen kann.
  • Wird route.preload aus einem Routenmodul exportiert, startet die Query der Route, bevor die Seitenkomponente gerendert wird.
  • SolidStart v2 wird über Vite-Plugins (Nitro v3, Cloudflare, Netlify) deployt und pflegt keine eigenen Hosting-Adapter.

Was ist SolidStart und wo steht v2?

SolidStart ist die Meta-Framework-Schicht über Solid. Solid rendert Komponenten. SolidStart ergänzt diese um Routing, Server-Rendering, Data Loading sowie eine Build- und Deploy-Pipeline.

SolidStart v2 ist seit dem 4. August 2026 stabil. Vinxi ist entfallen, stattdessen baut v2 auf der Environment API von Vite auf. Sie benötigen Node.js 24 oder neuer sowie Vite 8, und die Framework-Einstellungen befinden sich jetzt in vite.config.ts statt in app.config.ts. v2 ist für Solid v1 entwickelt. Laut der Ankündigung des Solid 2.0 Release Candidate erhält SolidStart nur noch Maintenance-Releases, und in Solid 2.0 übernimmt ein in den Solid-Core integrierter Start-Modus seine Rolle. Apps, die SolidStart bereits produktiv einsetzen, funktionieren weiterhin. Der folgende Code zielt auf Solid v1 und SolidStart v2 ab. Wenn Sie eine bestehende v1-App aktualisieren, folgen Sie dem Migrationsleitfaden für v1.

Ein SolidStart-Projekt anlegen

Um ein Projekt zu scaffolden, führen Sie den Solid-Initializer aus und wählen bei der Abfrage das SolidStart-Template:

npm init solid
# or: pnpm create solid
cd my-app
npm install

Die App wird in vite.config.ts konfiguriert. Das minimale Setup aus dem Getting-Started-Guide sieht so aus:

import { defineConfig } from "vite";
import { solidStart } from "@solidjs/start/config";

export default defineConfig({
  plugins: [solidStart()],
});

Für die Produktion kombinieren Sie solidStart() mit einem Server-Plugin, zum Beispiel Nitro v3. Laut der Konfigurationsreferenz zu solidStart gehören Nitro-Einstellungen nicht in solidStart(), sondern in einen separaten nitro-Key auf oberster Ebene.

Jede Datei unter src/routes wird entweder zu einer Seite oder zu einem API-Endpunkt. Die Seite zu API-Routen in v2 erläutert, dass Endpunkte denselben Regeln für die Zuordnung von Dateien zu Pfaden folgen wie Seiten. Ein integrierter ~-Alias verweist auf das App-Root-Verzeichnis, sodass ~/lib/db mit den Standardeinstellungen auf src/lib/db abgebildet wird.

Daten auf dem Server laden mit query und createAsync

In SolidStart stammen Routendaten aus einer asynchronen Funktion, die in query aus @solidjs/router eingeschlossen ist. Eine Komponente liest sie dann über createAsync aus. Dieses Muster verwenden die v2-Dokumentation zum Data Fetching. Laut Dokumentation funktioniert SolidStart v2 entweder mit Solid Router v1 oder mit TanStack Solid Router v1. Die Beispiele hier verwenden Solid Router.

Beginnen Sie mit einem Datenmodul unter src/lib/posts.ts. Es nutzt ein In-Memory-Array, damit das Beispiel ohne Datenbank läuft:

export type Post = { id: string; title: string; body: string };

const posts: Post[] = [
  { id: "1", title: "Hello SolidStart", body: "First post." },
  { id: "2", title: "Server functions", body: "Second post." },
];

export async function listPosts() {
  return posts.map(({ id, title }) => ({ id, title }));
}

export async function findPost(id: string) {
  return posts.find((p) => p.id === id) ?? null;
}

Die Route für die Beitragsliste:

import { For } from "solid-js";
import { createAsync, query, type RouteDefinition } from "@solidjs/router";
import { listPosts } from "~/lib/posts";

const getPostList = query(async () => {
  "use server";
  return listPosts();
}, "post-list");

export const route = {
  preload: () => getPostList(),
} satisfies RouteDefinition;

export default function PostsPage() {
  const list = createAsync(() => getPostList());
  return (
    <ul>
      <For each={list()}>
        {(post) => (
          <li>
            <a href={`/posts/${post.id}`}>{post.title}</a>
          </li>
        )}
      </For>
    </ul>
  );
}

Die Detailseite ist eine dynamische Route, die einen id-Parameter erhält. Die v2-Dokumentation zum Routing beschreibt die Dateinamen-Syntax für dynamische Segmente.

import { Show } from "solid-js";
import { createAsync, query, type RouteDefinition } from "@solidjs/router";
import { findPost } from "~/lib/posts";

const getPostById = query(async (id: string) => {
  "use server";
  return findPost(id);
}, "post-by-id");

export const route = {
  preload: ({ params }) => getPostById(params.id),
} satisfies RouteDefinition;

export default function PostPage(props: { params: { id: string } }) {
  const post = createAsync(() => getPostById(props.params.id));
  return (
    <Show when={post()} fallback={<p>Post not found.</p>}>
      {(p) => (
        <article>
          <h1>{p().title}</h1>
          <p>{p().body}</p>
        </article>
      )}
    </Show>
  );
}

Das zweite Argument von query ist der Cache-Key, daher sollte jede Query einen eigenen erhalten. Der Export route.preload startet die Query, bevor die Seitenkomponente gerendert wird. Das Laden der Daten beginnt also zeitgleich mit der Navigation.

Formulare, Mutationen und Revalidierung

Das Zurückschreiben von Daten auf den Server funktioniert anders als das Lesen. Eine Mutation muss den Zustand auf dem Server ändern und der Seite anschließend mitteilen, dass ihre gecachten Lesezugriffe veraltet sind. In v2 laufen Schreibvorgänge über action aus Solid Router, mit einer "use server"-Direktive im Action-Body, wenn die Arbeit auf dem Server erfolgen muss. Die v2-Seite zu Datenmutationen enthält die aktuellen Formularbeispiele, Pending- und Fehlerzustände sowie die Übergabe zusätzlicher Argumente mit .with().

Die Leseseite der Revalidierung knüpft an den vorherigen Abschnitt an. Jede query wird unter ihrem Key gecacht (oben "post-list" und "post-by-id"), und createAsync liest erneut, sobald dieser Cache-Eintrag revalidiert wird. Wenn eine Action erfolgreich ist, revalidiert Solid Router standardmäßig alle aktiven Queries auf der Seite. Um nur einige davon zu aktualisieren, übergeben Sie Keys an revalidate: getPostList.key adressiert alle Instanzen einer Query, getPostById.keyFor(id) eine einzelne. Die Dokumentation zum Data Fetching verweist für das Cache-Verhalten auf Solid Router, und die Revalidierungsseite des Routers erklärt es im Detail.

Klare, stabile Query-Key-Namen zahlen sich aus, wenn Sie die Revalidierung eingrenzen. Eine Mutation, die einen Beitrag hinzufügt, muss nur "post-list" aktualisieren, während eine Bearbeitung zusätzlich "post-by-id" benötigt.

Was bewirkt “use server”?

Steht die Direktive "use server" am Anfang eines Funktions-Bodys, läuft diese Funktion auf dem Server, selbst wenn sie aus einer Komponente aufgerufen wird. Deshalb kann eine so markierte Query Secrets aus process.env und Session-Daten lesen. Die v2-Dokumentation zum Data Fetching zeigt dies in ihrem Server-only-Beispiel mit useSession aus @solidjs/start/http.

In "use server" platzierenAußerhalb davon halten
Umgebungs-Secrets (process.env.*)Browser-APIs (window, localStorage, DOM)
Datenbank- und Session-ZugriffUI-State, der in Komponenten lebt
@solidjs/start/http-HelperAlles, was bei einem Klick ohne Request ausgeführt werden muss

In einer SolidStart-App gehört UI-State auf den Client. Der Server hält die Daten, Signals und Stores halten den Interaktionszustand – eine Aufteilung, die in State Management in SolidJS behandelt wird.

SolidStart v2 erkennt außerdem die Marker-Imports server-only und client-only. Fügen Sie einen davon zu einem Modul hinzu, bricht ein Import von der falschen Seite (Servercode im Client oder umgekehrt) den Dev-Server bzw. den Build ab, sodass der Fehler nie bei den Nutzern ankommt. Die Konfigurationsreferenz führt @solidjs/start/http und @solidjs/start/middleware als bereits server-only markiert auf. Während der Entwicklung steht zudem eine Toolbar zur Verfügung, die App-Fehler und Aufrufe von Server Functions anzeigt. Sie wird nie in einem Production-Build ausgeliefert.

Rendering-Modi in SolidStart

In SolidStart v2 wird das Rendering-Verhalten über das Plugin solidStart() und das damit kombinierte Deployment-Plugin konfiguriert, die beide in vite.config.ts deklariert werden. Die konzeptionellen Abwägungen zwischen Server-Rendering, Streaming und statischer Generierung finden Sie in den Top 10 Rendering Patterns. Dieser Abschnitt behandelt nur, wo diese Entscheidungen in SolidStart getroffen werden.

Da app.config.ts nicht mehr existiert, gelten Rendering-Flags aus der v1-Ära, die Sie in älteren Beiträgen finden, nicht mehr in der dort beschriebenen Form. Welche Optionen v2 bereitstellt, entnehmen Sie der Konfigurationsreferenz zu solidStart() und der Dokumentation der Deployment-Plugins.

Wird eine Seite auf dem Server gerendert, sehen Nutzer das Markup, bevor das Client-JavaScript es hydriert hat. Session Replays von SSR-Apps machen diese Lücke sichtbar: Ein Nutzer tippt auf einen Button, der korrekt dargestellt wird, aber nichts tut, und tippt erneut, sobald die Handler angehängt sind.

SolidStart v2 deployen

SolidStart v2 hat keine eigenen Hosting-Adapter. Das Deployment erfolgt über Vite-Plugins, und die v2-Ankündigung nennt drei unterstützte Ziele: das Nitro-v3-Vite-Plugin (laut dieser Ankündigung noch in der Beta), das Cloudflare-Vite-Plugin und das Netlify-Vite-Plugin. Der Getting-Started-Guide verweist auf eine Seite zu Deployment-Plugins, die die Konfiguration der Produktions-Runtime für jedes davon beschreibt.

Der eigentliche Preis für die Wahl von SolidStart gegenüber einem React-Stack ist das Ökosystem. React bietet weit mehr Komponentenbibliotheken von Drittanbietern, Auth-Integrationen und Hosting-Templates, und Solid-Teams schreiben mehr von diesem Glue Code selbst. Der Vergleich SolidJS vs. React stellt diese Lücke dem Rendering-Modell von Solid gegenüber. Beachten Sie außerdem, dass sich SolidStart v2 im Maintenance-Modus befindet, während Solid 2.0 auf den Start-Modus zusteuert.

Fazit

SolidStart v2 ist ein stabiler, Vite-nativer Weg, Solid-v1-Apps um Server-Rendering zu erweitern. Das Laden von Daten reduziert sich auf drei Bausteine: query, createAsync und eine "use server"-Direktive, ergänzt durch route.preload für frühzeitiges Fetching. Als nächster Schritt bietet es sich an, mit npm init solid ein Projekt aufzusetzen, die beiden oben gezeigten Beitragsrouten hinzuzufügen und anschließend anhand des Abschnitts zu Datenmutationen in der v2-Dokumentation eine Mutation einzubinden.

FAQs

Funktioniert SolidStart v2 mit Solid 2.0?

Nein. SolidStart v2 ist für Solid 1.x entwickelt, und kein SolidStart-Release zielt auf Solid 2.0 ab. Mit dem Solid 2.0 Release Candidate wird SolidStart abgelöst und seine Bestandteile wandern an andere Stellen: Der Solid-Core übernimmt nun die Server Functions, der Start-Modus das Serving, und ein separates, router-neutrales Paket kümmert sich um das dateisystembasierte Routing. Bestehende SolidStart-Apps funktionieren weiterhin, SolidStart erhält weiterhin Maintenance-Releases, und ein offizieller Migrationsleitfaden beschreibt den Umstieg auf den Start-Modus.

Was ist der Unterschied zwischen TanStack Start und SolidStart mit TanStack Router?

Es handelt sich um getrennte Optionen. SolidStart v2 ist router-agnostisch und läuft entweder mit dem offiziellen Solid Router v1 oder mit TanStack Solid Router v1, sodass Sie TanStack-Routing nutzen können, ohne SolidStart zu verlassen. TanStack Start ist ein eigenständiges Metaframework mit einer Solid-Variante, die als @tanstack/solid-start veröffentlicht wird und bereits ein Beta-Release für Solid 2.0 hat. Für Solid 2.0 kombiniert der Starter fullstack-tanstack den Start-Modus mit TanStack Router und TanStack Query.

Was sind Single-Flight Mutations in SolidStart?

Bei Single-Flight Mutations werden die aktualisierten Daten in derselben Server-Response zurückgesendet wie die Mutation selbst. Wenn eine serverseitige Action Daten ändert, die die aktuelle Ansicht per Preload geladen hat, oder auf eine Seite weiterleitet, deren Daten per Preload geladen werden, revalidiert SolidStart diese Daten auf dem Server und liefert sie im selben Roundtrip aus. Der Client muss keine zweite Runde von Requests absetzen, sodass nach einem Schreibvorgang kein Request-Wasserfall entsteht.

Was ändert sich beim Upgrade einer SolidStart-v1-App auf v2?

Das Upgrade erfordert Node.js 24 und Vite 8. Die Framework-Konfiguration wandert von app.config.ts in vite.config.ts, wo solidStart() als Vite-Plugin registriert wird, und die Environment API von Vite ersetzt Vinxi. Der offizielle Migrationsleitfaden beschreibt außerdem die Änderungen bei Importpfaden, TypeScript-Umgebungstypen, der Server-Runtime und der Middleware. Prüfen Sie Importpfade und Middleware-Code aus v1 anhand des Leitfadens, statt sie unverändert zu übernehmen.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.