Ship it your way.
Bare, Docker, or Kubernetes.
The app you write doesn’t change with the target — only the packaging does. Pick a baseline at create-project time or switch later with one command. Self-host on a single box, a Compose stack, or a Kubernetes cluster; offload edges to serverless. Running the same runtime managed on Voltro Cloud is coming soon.
# pick a baseline at create time…
$ voltro create-project my-app --baseline compose
# …or switch later
$ voltro baseline set helm
# build + run, anywhere Node + Postgres run
$ voltro build && voltro startPick a target; the app stays the same.
Three baselines
bare gives a systemd unit + env example; compose gives Dockerfiles + a Postgres docker-compose (dev + prod variants); helm gives a Kubernetes chart with per-env values, Deployment, Service, Ingress and a Postgres StatefulSet. Switch with voltro baseline set.
Self-host anywhere
Node 24+, Postgres 16+ (pgvector for AI/search, wal_level=logical for subscriptions), and a reverse proxy (Caddy / nginx / Cloudflare). Optional Redis + object storage. No Kubernetes required — a single origin is enough.
Serverless functions
*.serverless.ts units run self-hosted on Node or offload to Cloudflare Workers / Scaleway Functions. They get HttpClient + ctx.env only — reach for one when you need process isolation or independent scaling; otherwise prefer an action.
Static-site deploy
voltro static ships a prerendered dist/ to Cloudflare Pages, S3-compatible hosts (AWS / Scaleway / R2 / B2 / MinIO) or Netlify — Content-Type, Cache-Control and SPA fallback set for you. A render-mode gate blocks non-static apps unless you opt in.
Scale to zero
dormancy: "sleep" plus the voltro dormancy orchestrator idle apps down to roughly zero cost; they wake on the next request, WebSocket upgrade, or a due scheduled job. Needs a SQL store to track wakeups.
Or run it managed (coming soon)
Voltro Cloud will run the exact same runtime, so nothing about your app changes — it adds managed infrastructure, a deploy pipeline and hosted observability. Managed cloud hosting is coming soon; today you self-host, and you can eject back to a baseline any time.
The job definition doesn’t care where it runs.
One app, any topology
The same schedule runs unchanged on one box, a multi-instance fleet, or a Kubernetes CronJob — voltro schedule-manifest even generates the k8s / AWS / GCP / Azure manifest for you. Because deploy config is packaging, not code, moving from Compose to Helm — or to Cloud and back — never touches a handler.
What a production deploy costs to run.
database engines it can point at — the deploy shape does not change with the choice
published packages, of which a deployment runs the handful your app imports
From your repository to a serving container.
- 1
Build
The serve path is compiled into one artefact instead of resolving hundreds of modules at boot — measured at roughly 176ms to ready against roughly 1010ms without it, on the same fixture.
- 2
Apply the schema
A pre-deploy job diffs the declaration against the live database. It refuses rather than guessing when its answer would differ from the serving process's.
- 3
Start
One container and a database is a complete deployment. Compose, Helm and a plain systemd target are baselines you pick at scaffold time, not rewrites.
- 4
Roll
Shutdown drains: in-flight requests finish, timers and change subscriptions are released, and the analytics queue is flushed into the sink before the process exits.
Deployment, in depth.
What does a Voltro app actually need to run?
A Node process and a database. That is the whole runtime requirement — no message broker, no workflow service, no separate cache tier, no sidecar. Durable workflows journal to your database, scheduled jobs coordinate through it, and the cache defaults to memory until you decide otherwise.
Everything else is additive and opt-in. Redis buys cross-replica reactivity on dialects without a fleet-wide change feed, and a shared cache once you have several instances; neither is required to be correct, only to scale a particular way.
That matters most at the beginning and at the end. A first deploy is one container and a managed Postgres, and the same code later runs behind a load balancer with replicas — without a re-architecture, because the parts that usually force one are already coordinated.
How do I get from a repository to something running?
Through a baseline: a deploy surface scaffolded alongside your project. A Docker Compose stack for a single box, a Helm chart for Kubernetes, or nothing at all if you already have a pipeline. The application is identical in each; only the layer around it differs.
`voltro build` precompiles the serve path into a single artefact, so production loads one file instead of resolving hundreds of modules at boot. Measured on the framework's own fixture that is roughly a five-fold improvement, and the gain is larger on a small container where module resolution dominates a cold start.
The build also produces a self-contained web output — the server bundle inlines what it needs — so a production image ships almost no node_modules. A static site with no native dependency drops it entirely.
What about serverless and static sites?
Both are first-class rather than a workaround. A standalone function bundle deploys to Node, Cloudflare or Scaleway with `voltro serverless`; a static site publishes to Cloudflare Pages, S3 or Netlify with `voltro static`. Neither requires a long-running server.
The combination is the common shape for a small product: a statically rendered marketing site on a CDN plus one serverless function for the single dynamic thing, like a contact form. A template ships that whole shape so you are not assembling it.
The choice is per app, not per project. A workspace can hold a long-running api, a static marketing site and a serverless function library, deployed to three different places from one repository.
How does the app behave in production versus development?
The framework treats that difference as a hazard rather than a detail. Development and production are two independent boot paths, and a capability wired into one but not the other works locally and silently no-ops in production — which has happened here, repeatedly, and is now guarded by a check derived from the source rather than by a curated list.
Production is also stricter on purpose. A missing session secret is a refusal to boot, not a development fallback that quietly signs real traffic. A failing startup module refuses the boot rather than warning and serving anyway. A procedure without an access decision stops the process.
For hosts that scale to zero, `voltro dormancy` fronts the app, stops it when idle and wakes it on the next request — a single-node answer that does not require a managed platform.
The deploy paths, and when each fits.
| Path | Fits when |
|---|---|
| Compose baseline | One box or a VM: the app, a database and optional Redis, scaffolded with the project. |
| Helm baseline | Kubernetes: a chart you own, with the app's replica and scheduling behaviour already coordinated. |
| Serverless functions | Isolated work with no long-running server — Node, Cloudflare or Scaleway. |
| Static site | Pre-rendered pages to a CDN: Cloudflare Pages, S3 or Netlify, zero JS where the page allows it. |
| Scale to zero | Single-node dormancy: stop when idle, wake on the next request, without a managed platform. |
| Managed cloud | The control plane registers and observes self-hosted apps today; managed deploy is coming. |
Frequently asked questions
Do I need Kubernetes?
No. A single container and a database is a complete deployment, and the same code scales out later without re-architecture. Helm is one baseline among several, offered because some teams already run Kubernetes — not because the framework needs it.
Do I need Redis?
Only for specific behaviour: cross-replica reactivity on dialects without a fleet-wide change feed, and a shared cache across instances. On Postgres or MySQL/MariaDB with one instance you need neither.
How large is a production image?
Small, because the build is self-contained: the server bundle inlines the framework, so the runtime needs almost no node_modules. A static or SSR site with no native dependency can ship none at all — measured at roughly a third of the naive tree on the framework's own apps.
Can I deploy to my own infrastructure?
That is the default posture. The framework is a runtime next to your database — your connection string, your backups, your access rules — and nothing is proxied through third-party infrastructure unless you explicitly choose a managed target.
What is different between voltro dev and production?
Production is stricter, on purpose: no development fallback for a session secret, a failing startup module refuses the boot, and an undecided access declaration stops the process. The two boot paths are also guarded against drift, because a capability wired in one and not the other is the class of bug that only shows up in production.
Deployment ties into operations.
Open the framework. See it for yourself.
Every primitive on this page is in the framework today. Clone the starter, run `voltro dev`, and have it on screen in two minutes.