Two Solid apps, two deploy shapes
Solid comes in two flavors that deploy very differently:
- SolidJS (with Vite) builds to a static SPA — HTML, CSS, JS files. Deploy it as a static site; it's free and globally fast.
- SolidStart is the full-stack meta-framework with SSR, server functions, and API routes. It needs a running server, so deploy it as a container.
Knowing which you have determines everything. Let's cover both.
Path A: SolidJS SPA as a static site
A Vite-based Solid app builds to a dist/ folder:
// package.json
{
"scripts": {
"build": "vite build",
"preview": "vite preview"
}
}npm run build # outputs to dist/Deploy as a PandaStack static site. The platform auto-detects the Vite framework, runs vite build, and serves dist/. Static builds run in pandastack.ai microVMs, and the output is served globally. Static sites are unlimited on Pro and Premium, and the free tier includes 5 static sites — so a Solid SPA can be hosted at $0/mo.
SPA routing fallback
Client-side routing (solid-router) needs all unknown paths to serve index.html, or deep links 404. For a static SPA this is the standard SPA fallback — configure your routes to rewrite to index.html. Most static hosting (PandaStack included) supports an SPA fallback for exactly this.
Path B: SolidStart SSR as a container
SolidStart uses Vinxi/Nitro under the hood and can target a Node server. Set the Node preset:
// app.config.js
import { defineConfig } from '@solidjs/start/config';
export default defineConfig({
server: { preset: 'node-server' },
});Build produces a server bundle you run with Node:
{
"scripts": {
"build": "vinxi build",
"start": "node .output/server/index.mjs"
}
}The Nitro Node output reads the PORT env var automatically, so it binds to the platform's injected port without changes.
FROM node:20.18-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20.18-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]Or skip the Dockerfile — PandaStack auto-detects Node and the build/start commands.
Step: Add data with a managed database
SolidStart server functions can talk to a database. Attach a managed PostgreSQL and read the injected DATABASE_URL inside a server-only module:
// db.server.ts
import postgres from 'postgres';
export const sql = postgres(process.env.DATABASE_URL!);Use it inside a "use server" function or a route's server handler so it never ships to the client.
Step: Deploy
Connect your repo and push:
git push origin mainFor the SPA path, the static build runs and deploys to the global edge. For the SSR path, the build runs in a rootless BuildKit K8s Job pod, ships to Artifact Registry, and Helm-deploys. Either way you get live build logs, a custom domain, and automatic SSL.
Which should you choose?
| SolidJS SPA | SolidStart SSR | |
|---|---|---|
| Output | Static files | Node server |
| Deploy as | Static site (free) | Container |
| SEO | Client-rendered | Server-rendered |
| Data fetching | Client / external API | Server functions |
| Cost | $0 on free static | Web service tier |
If you don't need SSR or server functions, the SPA path is simpler and free. Reach for SolidStart when you need server-side rendering, server functions, or co-located data access.
References
- [SolidStart — deployment](https://docs.solidjs.com/solid-start/getting-started)
- [SolidStart configuration & presets](https://docs.solidjs.com/solid-start/reference/config/define-config)
- [Vite — static deploy](https://vite.dev/guide/static-deploy)
- [Nitro deployment presets](https://nitro.build/deploy)
---
Solid scales from a free static SPA to a full SSR app without changing frameworks. Host the SPA free or run SolidStart as a container with an auto-wired Postgres — start on PandaStack's [free tier](https://dashboard.pandastack.io) and pick the path that fits.