Hosting Providers
Zero-config web deployment with bini-deploy - generates hosting config and pushes straight to GitHub.
bini-deploy scans your project, generates the right hosting configuration for your target provider, and pushes it straight to GitHub - no YAML spelunking, no platform-specific docs to read first.
It is bundled into every Bini.js scaffold and exposed as npm run deploy. This page covers the web hosting providers it supports. For desktop and mobile targets, see Deployment Overview.
Installation
Already included in every Bini.js scaffold. To add it to an existing project:
$ npm install --save-dev bini-deploy
Supported Providers
| Provider | Runtime | Config generated |
|---|---|---|
| Node.js | Node | None |
| Netlify | Edge Functions (Deno) | netlify.toml |
| Vercel | Node.js Runtime | vercel.json |
| Cloudflare Workers | Workers | wrangler.toml |
| Deno Deploy | Deno | server/index.ts |
bini-server, a zero-dependency production server. Choosing it skips config generation entirely - there is nothing to adapt, so bini-deploy just commits and pushes.How it works
- Scan - scans
src/app/api/for route files - Generate - creates the platform-specific entry file and config
- Clean - removes leftover entry files, config, and directories from any previously selected platform, including when switching to Node or a native platform
- Push - commits and pushes everything to your GitHub repository
- Deploy - your hosting provider deploys automatically from GitHub
Usage
Every Bini.js scaffold already has this wired into package.json, so deploying is just:
$ npm run deploy
This runs bini-deploy interactively - it prompts you to pick a platform (web, windows, macos, linux, android, ios) and, if you choose web, a hosting provider (node, netlify, vercel, cloudflare, deno).
For scripts and CI, skip the prompts with flags:
$ npx bini-deploy --platform web --hosting vercel --repo https://github.com/you/your-app --yes| Flag | Description |
|---|---|
--platform | web, windows, macos, ios, linux, android |
--hosting | web only - node (default), netlify, vercel, cloudflare, deno |
--repo | GitHub repository URL to push to |
--generate-entry | generate only the production entry file - netlify, vercel, cloudflare, deno |
--yes, -y | skip interactive prompts and use the flags provided |
Node.js
The default hosting choice. bini-server reads your API handlers directly from src/app/api/ at request time - no build step, no generated entry file.
$ npm run deploy
Pick web, then Node.js (the default) when prompted:
? Select hosting provider:> Node.js (default - bini-server)NetlifyVercelCloudflare WorkersDeno Deploy↑↓ navigate • ⏎ select
Works out of the box on Railway, Render, Fly.io, or a bare VPS with pm2. See Production Server for the full runtime reference.
Netlify
API routes run as Netlify Edge Functions.
$ npm run deploy
Pick web, then Netlify when prompted:
? Select hosting provider:Node.js (default - bini-server)> NetlifyVercelCloudflare WorkersDeno Deploy↑↓ navigate • ⏎ select
Generates:
netlify.tomlnetlify/edge-functions/api.ts
[build]
command = "vite build"
publish = "dist"
[[edge_functions]]
path = "/api/*"
function = "api"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200fs, nodemailer) will not work there.Vercel
API routes run on Vercel's Node.js Runtime.
$ npm run deploy
Pick web, then Vercel when prompted:
? Select hosting provider:Node.js (default - bini-server)Netlify> VercelCloudflare WorkersDeno Deploy↑↓ navigate • ⏎ select
Generates:
vercel.jsonapi/index.ts
api/index.ts before running your build - bini-deploy commits it for you, so it is already there when CI runs. It imports hono as an npm package, so bini-deploy checks it is installed and tells you the exact install command if it is missing.Cloudflare Workers
API routes run as a Cloudflare Worker.
$ npm run deploy
Pick web, then Cloudflare when prompted:
? Select hosting provider:Node.js (default - bini-server)NetlifyVercel> Cloudflare WorkersDeno Deploy↑↓ navigate • ⏎ select
Generates:
wrangler.tomlworker.ts
Or deploy manually with Wrangler once the entry file exists:
$ npx wrangler deploy
hono as an npm package - bini-deploy verifies it is installed before generating the entry file.Deno Deploy
API routes run on Deno.
$ npm run deploy
Pick web, then Deno when prompted:
? Select hosting provider:Node.js (default - bini-server)NetlifyVercelCloudflare Workers> Deno Deploy↑↓ navigate • ⏎ select
Generates:
server/index.ts
In the Deno Deploy dashboard, set:
- Entrypoint:
server/index.ts - Runtime: Dynamic App
hono directly from a URL, so no local install check is needed for these two.API Routes & Hono
Every provider mounts the same file-based routes from src/app/api/, dynamic segments and catch-alls included:
Each route exports a default handler that accepts a Request and returns a Response (or a JSON-serializable value):
export default async function handler(req: Request) {
const id = new URL(req.url).pathname.split('/').pop();
return { id, name: 'Ada Lovelace' };
}Imports from hono are detected automatically and mounted as a full Hono app instead:
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.json({ message: 'Hello from Hono!' }));
app.post('/', async (c) => {
const body = await c.req.json();
return c.json({ received: body });
});
export default app;"type": "module", Node's native ESM loader requires relative imports to include their file extension. bini-deploy's generated imports already include .js, but if your route files import local helpers (e.g. ./utils), include the extension there too (./utils.js) or the deployed function will crash with ERR_MODULE_NOT_FOUND even though the build succeeds.Automatic CORS
API routes get permissive CORS headers out of the box on every non-Node hosting adapter - Netlify, Vercel, Cloudflare, and Deno - so your frontend can call them without extra setup.
Git Push Behavior
- Existing remote - used without modification
- New projects - the provided URL is added as
origin - No remote updates - once a remote is set, it is never changed
- Always main - always pushes to
main, automatically renamingmasterif needed - Remote-ahead recovery - if the remote has commits you do not have locally (e.g. GitHub auto-created a README), bini-deploy fetches and merges automatically with
--allow-unrelated-histories -X ours, keeping your local version of any file that exists on both sides. A warning prints before the merge runs; a real conflict stops the process and prints manual recovery steps
bini-deploy multiple times without accidentally pushing to the wrong repository.Requirements
| Requirement | Version |
|---|---|
| Node.js | >= 18 |
| Vite | >= 6 |
| git | available on your PATH |
| GitHub repository | created ahead of time, to push to |