Deployment
Deploy your documentation to any hosting platform
Last updated March 18, 2026
Petit builds your docs for any hosting platform. Set the deploy
field in your config to target a specific platform, then run the
build command.
npx @ephem-sh/petit buildpnpm dlx @ephem-sh/petit buildbun x @ephem-sh/petit buildyarn dlx @ephem-sh/petit buildPetit scaffolds a .petit/ workspace during the build with all
required dependencies. You don't need a package.json or
node_modules in your project.
Deploy targets
Set the deploy field in petit.config.json to match your
hosting platform:
{
"title": "My Docs",
"deploy": "cloudflare"
}
| Property | Type | Default | Description |
|---|---|---|---|
node | string | "node" | Default. Builds with Nitro for any Node.js server or Docker container |
cloudflare | string | - | Cloudflare Workers via @cloudflare/vite-plugin |
netlify | string | - | Netlify via @netlify/vite-plugin-tanstack-start |
vercel | string | - | Vercel with auto-detection via Nitro |
bun | string | - | Bun runtime via Nitro with the bun preset |
Cloudflare Workers
Cloudflare Workers provides edge deployment with global distribution. Set the deploy target in your config:
{
"title": "My Docs",
"deploy": "cloudflare",
"siteUrl": "https://docs.example.com"
}
Petit generates a wrangler.jsonc and installs
@cloudflare/vite-plugin and wrangler automatically
inside the .petit/ workspace during the build.
CI/CD with Cloudflare Workers
Create a new Worker in the Cloudflare dashboard and connect your Git repository. Configure the build settings:
| Property | Type | Default | Description |
|---|---|---|---|
Build command | string | npx @ephem-sh/petit@latest build | Scaffolds .petit/ workspace, installs deps, runs vite build |
Deploy command | string | cd .petit && npx wrangler deploy | Runs wrangler from inside .petit/ where node_modules lives |
Root directory | string | / | Your repository root |
Add these build environment variables under Settings > Build > Variables and secrets (the build section, not the runtime one):
| Property | Type | Default | Description |
|---|---|---|---|
SKIP_DEPENDENCY_INSTALL | string | true | Skips Cloudflare's auto-install step (Petit handles its own deps) |
NODE_OPTIONS | string | --max-old-space-size=4096 | Increases memory for the vite build process |
Note: The
SKIP_DEPENDENCY_INSTALLvariable must be set in the build variables section. Cloudflare's auto-install runs before the build command and will fail on monorepo lockfiles.
Local deployment
To deploy from your local machine, build first, then run
wrangler from the .petit/ directory:
npx @ephem-sh/petit buildpnpm dlx @ephem-sh/petit buildbun x @ephem-sh/petit buildyarn dlx @ephem-sh/petit buildcd .petit && npx wrangler login && npx wrangler deploy
Netlify
Netlify deploys via the @netlify/vite-plugin-tanstack-start
plugin, which Petit installs automatically during the build.
Set the deploy target in your config:
{
"title": "My Docs",
"deploy": "netlify",
"siteUrl": "https://docs.example.com"
}
Netlify requires two files in your repository to bypass its automatic dependency installation, which fails on monorepos and projects without a lockfile.
Repository setup
Add these two files to your repository root:
- Create a
netlify.tomlfile:
[build]
base = ".netlify-skip/"
command = "cd .. && npx @ephem-sh/petit@latest build --netlify"
publish = "dist/client/"
[build.environment]
NODE_OPTIONS = "--max-old-space-size=4096"
- Create a a empty
.netlify-skipfolder in your root and place a package.json inside it.netlify-skip/package.jsonfile:
{"private":true}
The base directory points Netlify's install step at the
empty .netlify-skip/ folder, which finishes instantly. The
build command changes back to the repository root and runs
Petit with the --netlify flag, which moves the SSR function,
static assets, and dependencies into the correct locations
after the build completes.
Dashboard configuration
Import your repository in the Netlify dashboard. The
netlify.toml file configures everything automatically.
No dashboard overrides are needed.
Vercel
Vercel deploys via Nitro with auto-detection. Set the deploy target:
{
"title": "My Docs",
"deploy": "vercel",
"siteUrl": "https://docs.example.com"
}
Import your repository in the Vercel dashboard and configure the build settings:
| Property | Type | Default | Description |
|---|---|---|---|
Build Command | string | npx @ephem-sh/petit@latest build | Scaffolds .petit/ workspace, installs deps, runs vite build |
Output Directory | string | (leave empty) | Vercel auto-detects .vercel/output/ generated by Nitro |
Install Command | string | echo skip | Petit handles its own install during the build step |
Root Directory | string | ./ | Your repository root |
Petit scaffolds a .petit/ workspace during the build, installs
all dependencies there, and runs the vite build. Nitro outputs
to .vercel/output/ which Vercel picks up automatically.
No package.json or node_modules needed in your project root.
Railway
Railway provides instant deployments with zero configuration
files. The default node deploy target works with Railway's
Railpack builder. Set the deploy target in your config:
{
"title": "My Docs",
"deploy": "node",
"siteUrl": "https://docs.example.com"
}
Connect your repository in the Railway dashboard and configure the service settings:
| Property | Type | Default | Description |
|---|---|---|---|
Build command | string | npx @ephem-sh/petit@latest build | Scaffolds .petit/ workspace, installs deps, runs vite build |
Start command | string | node .petit/.output/server/index.mjs | Starts the Nitro server (reads PORT from Railway automatically) |
Add this variable under Variables in your service settings:
| Property | Type | Default | Description |
|---|---|---|---|
RAILPACK_INSTALL_CMD | string | mkdir -p node_modules | Skips Railpack's auto-install step (Petit handles its own deps) |
Nitro reads Railway's PORT environment variable automatically.
No additional configuration is needed.
Note: If your repository has a
package.jsonwith anenginesfield, set it to Node 24 or higher. If you don't have apackage.json, set theRAILPACK_NODE_VERSIONenvironment variable to24in your Railway service settings.
Node.js and Docker
The default node target works for any Node.js server or Docker
container. Build and start the server:
npx @ephem-sh/petit buildpnpm dlx @ephem-sh/petit buildbun x @ephem-sh/petit buildyarn dlx @ephem-sh/petit buildnode .petit/.output/server/index.mjs
The server starts on port 3000 by default. Static assets are
served from .petit/.output/public.
For Docker, use a multi-stage build:
FROM node:24-slim AS build
WORKDIR /app
COPY . .
RUN npx @ephem-sh/petit build
FROM node:24-slim
WORKDIR /app
COPY --from=build /app/.petit/.output .output
CMD ["node", ".output/server/index.mjs"]
Bun
Bun requires React 19. Set the deploy target:
{
"title": "My Docs",
"deploy": "bun",
"siteUrl": "https://docs.example.com"
}
npx @ephem-sh/petit buildpnpm dlx @ephem-sh/petit buildbun x @ephem-sh/petit buildyarn dlx @ephem-sh/petit buildbun .petit/.output/server/index.mjs
Static export
For static hosting without a server, the build output at
.petit/.output/public contains all static assets. You can
serve this directory with any static file server:
npx serve .petit/.output/public
SEO in production
To get full SEO support (sitemap, OG images, robots.txt, and
LLM endpoints), set siteUrl in your config before building:
{
"siteUrl": "https://docs.example.com"
}
See the SEO reference for details on what gets generated.
Image optimization
Petit converts PNG and JPG images to WebP at build time and generates responsive sizes (640px, 1024px, 1920px). This runs automatically during build if sharp is installed.
Offline support
The built site includes a service worker that caches pages after the first visit. Returning visitors can browse cached pages without a network connection. The service worker updates the cache in the background when a connection is available.

