Qwik takes a different approach to front-end performance: instead of hydrating the whole app on load, it *resumes* from server-rendered HTML and downloads JavaScript only when interaction demands it. For deployment, what matters is choosing the right Qwik City adapter and output mode. Let's go through it.
Adapters decide your output
Qwik City uses adapters to target deployment platforms. The two general-purpose ones are the Node.js Express/middleware adapter and the static-site adapter.
Add the Node server adapter:
npm run qwik add expressThen build for production:
npm run buildThis produces a Node server entry (commonly server/entry.express.js) plus client assets. For a static site, add the static adapter instead and build:
npm run qwik add static
npm run buildResumability and why it matters in production
Because Qwik defers JavaScript execution, the server-rendered HTML is the product users see first. A correct SSR deployment is what makes resumability work — if you accidentally ship only static HTML for an app that needs server endpoints, your routeLoader$ and routeAction$ server logic won't run. Use the static adapter only for sites whose data is known at build time.
Server endpoints
Qwik City's routeLoader$, routeAction$, and server$ functions execute on the server. They're where you talk to a database or use secrets:
export const useProduct = routeLoader$(async (event) => {
const id = event.params.id
return await db.product.findById(id)
})Any app using these needs the Node server output, not the static one.
Running and configuring the Node server
The Express adapter produces a standard Node server. Start it and ensure it binds the platform port:
node server/entry.express.jsThe generated server reads PORT from the environment. In Qwik, client-exposed variables must be prefixed with PUBLIC_; everything else stays server-side. Read server-only secrets inside loaders and actions, never in components.
A Dockerfile
FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app ./
RUN npm ci --omit=dev
EXPOSE 3000
CMD ["node", "server/entry.express.js"]Deploying on PandaStack
SSR Qwik (server endpoints): deploy as a container app. PandaStack detects Node, runs the build, and serves the Express output via Helm with automatic SSL. Set PORT, PUBLIC_*, and secret variables in the [dashboard](https://dashboard.pandastack.io). Attach a managed database if your loaders need one — DATABASE_URL is injected automatically.
Static Qwik: deploy as a static site. PandaStack builds it in pandastack.ai microVMs and serves it from a CDN with free SSL. Qwik's tiny initial JavaScript payload makes static Qwik sites exceptionally fast to first interaction.
| Adapter | Output | PandaStack app type |
|---|---|---|
static | HTML + assets | Static site |
express (Node) | Node server | Container app |
A performance note
Qwik's whole premise is shipping minimal JavaScript. On a CDN-backed static deploy you'll see excellent Core Web Vitals because there's almost nothing to execute on load. For SSR apps, keep your server endpoints fast — they're on the critical path for the first paint.
References
- [Qwik City deployment overview](https://qwik.dev/docs/deployments/)
- [Qwik Node deployment adapter](https://qwik.dev/docs/deployments/node/)
- [Qwik static site adapter](https://qwik.dev/docs/deployments/static-ssg/)
- [Qwik: resumability vs hydration](https://qwik.dev/docs/concepts/resumable/)
Qwik's speed pairs naturally with a CDN-backed static deploy. Try PandaStack's free tier — static sites and container apps both included — at [dashboard.pandastack.io](https://dashboard.pandastack.io).