Deploy Vite apps anywhere.
The Universal Deploy project enables any Vite app (vanilla Vite, Astro, Vike, TanStack Start, ...) to be deployed anywhere (Netlify, Cloudflare, Vercel, self-hosted, ...), in a zero-config fashion.
Our approach follows Netlify's RFC: the @universal-deploy/* packages provide a flexible toolset of low-level utilities and conventions, enabling integrations that are both flexible and seamless between Vite apps and deployment providers.
Note
The @universal-deploy/* packages are only used internally by frameworks and deployment providers — users don't see the existence of Universal Deploy.
This repository is a POC that solves the issue 1 and 3 of Netlify's RFC — "Server entry point location" and "Routing metadata". It demonstrates how a deployment target (Netlify, Cloudflare, Node, etc.) can find and use the different server entries defined by a framework with minimal API.
- For users: zero-config deployment — apps work out-of-the-box with the preferred deployment provider. No third-party package installation required other than the official Vite plugin of the deployment provider.
- For framework maintainers: standardized way to register server entries and routing metadata, making the framework compatible with deployment providers with a single integration.
- For deployment providers: automatic discovery and handling of server entries. No more custom logic for every framework; just read from the global store.
- Universal Routing: Uses a common routing format (
rou3) that is understood by all participants. - Minimal Conventions: Low-level utilities that are easy to adopt and don't get in the way of framework-specific logic.
Frameworks can register their server entries and routing information into a global store. This allows deployment providers to automatically discover and handle them.
Use @universal-deploy/store to register server entries with routing information:
import { addEntry } from "@universal-deploy/store";
addEntry({
id: "./src/server/api.ts",
route: "/api/*",
method: "GET",
});Note
addEntry isn't a definitive API; a common convention between all actors has yet to be established.
Call addEntry at any point, preferably before configResolved hooks.
For extensive documentation on how to integrate your framework, see the Framework Developer Guide.
Deployment providers read from the global store or use the provided catchall entry to handle routing and server entry discovery.
- For unique server entry: Set
rolldownOptions.inputtocatchAllEntry. This virtual entry will be resolved by thecatchAllplugin. - For multiple server entries: Use
getAllEntriesin apostconfigEnvironmenthook and setrolldownOptions.input. - Vite Plugin: The
universalDeploy()plugin automatically defaults to the Node.js adapter if no other supported deployment target is found.
For implementation examples, see:
adapter-node(Node.js, Bun, Deno)adapter-netlifyvite-plugin-vercel@11
Note
@cloudflare/vite-plugin works OOTB with Universal Deploy.
See the Plugins documentation for more details.
examples/tanstack-start: TanStack Start app deployed to Netlify, Cloudflare, Vercel, or Node.js/Bun/Deno.- Minimal examples:
- Netlify's RFC
- Vike's journey (that led us to Universal Deploy)
- Introducing Universal Deploy — 🚧
- Introducing Photon October 28, 2025
- Introducing
vike-serverMarch 26, 2025
MIT