Deploy to Vercel
Deploy ObjectStack applications to Vercel with the Hono server adapter.
Deploy to Vercel
ObjectStack 11 deploys to Vercel in server mode — serverless functions running the Hono adapter (@objectstack/hono). The published ObjectStack Studio/console ships as a static Vite SPA that points at a separate ObjectStack server (via VITE_SERVER_URL).
Removed in 11. The in-browser MSW mode (@objectstack/plugin-msw) and the Next.js adapter (@objectstack/nextjs) are no longer published — use the Hono server path below.
Server Mode (Serverless Functions)
In Server mode, ObjectStack runs inside Vercel Serverless Functions. API requests are handled by real backend logic with a real database.
Architecture
┌─── Vercel ────────────────────────────────────────────────────┐
│ │
│ Static Assets (React SPA) │
│ ┌───────────────────────────────────┐ │
│ │ /index.html, /assets/* │ │
│ └───────────────────────────────────┘ │
│ │
│ Serverless Functions │
│ ┌───────────────────────────────────┐ │
│ │ /api/[...objectstack] │ │
│ │ → ObjectKernel │ │
│ │ → ObjectQL │ │
│ │ → PostgreSQL / MongoDB / ... │──── External DB │
│ └───────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘Hono serverless function (@objectstack/hono)
This is a valid self-contained pattern when you want to ship a Vite SPA and its API from a single Vercel project: the SPA is served as static assets, and a Hono-based serverless function handles /api/* requests.
The published ObjectStack Studio/console (@object-ui/console) does not use this topology. It deploys as a pure static SPA with no api/ function — it is meant to be embedded in, or pointed at, a separate ObjectStack server via VITE_SERVER_URL. For that separate server, prefer the CLI (objectstack serve) over a hand-rolled Hono function.
1. Create the kernel singleton (api/_kernel.ts — prefixed with _ to prevent Vercel from creating a route):
// api/_kernel.ts
import { ObjectKernel, DriverPlugin, AppPlugin } from '@objectstack/runtime';
import { ObjectQLPlugin } from '@objectstack/objectql';
import { InMemoryDriver } from '@objectstack/driver-memory';
import { createHonoApp } from '@objectstack/hono';
import { Hono } from 'hono';
import appConfig from '../objectstack.config';
let _kernel: ObjectKernel | null = null;
let _app: Hono | null = null;
async function ensureKernel(): Promise<ObjectKernel> {
if (_kernel) return _kernel;
_kernel = new ObjectKernel();
await _kernel.use(new ObjectQLPlugin());
await _kernel.use(new DriverPlugin(new InMemoryDriver(), 'memory'));
await _kernel.use(new AppPlugin(appConfig));
await _kernel.bootstrap();
return _kernel;
}
export async function ensureApp(): Promise<Hono> {
if (_app) return _app;
const kernel = await ensureKernel();
_app = createHonoApp({ kernel, prefix: '/api/v1' });
return _app;
}InMemoryDriver keeps this snippet self-contained, but on serverless all data
is lost on every cold start — fine for a demo, wrong for anything real. Before
going past a proof of concept, swap the driver for a real database (see
Database Drivers) and point OS_DATABASE_URL at it.
2. Create the API entrypoint (api/index.ts):
// api/index.ts
import { Hono } from 'hono';
import { handle } from 'hono/vercel';
import { ensureApp } from './_kernel';
const app = new Hono();
app.all('*', async (c) => {
const inner = await ensureApp();
return inner.fetch(c.req.raw);
});
export default handle(app);3. vercel.json:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "vite",
"buildCommand": "vite build",
"outputDirectory": "dist",
"build": {
"env": {
"VITE_USE_MOCK_SERVER": "false",
"VITE_SERVER_URL": ""
}
},
"rewrites": [
{ "source": "/api/(.*)", "destination": "/api" },
{ "source": "/((?!api/).*)", "destination": "/index.html" }
]
}Setting VITE_SERVER_URL to empty string tells the client SDK to use same-origin API calls. The first rewrite routes all /api/* sub-paths to the api/index.ts serverless function. The second rewrite excludes /api/ paths so all other paths serve the SPA.
Environment Variables
Configure these in Vercel Project Settings → Environment Variables:
Studio / SPA build
| Variable | Description |
|---|---|
VITE_USE_MOCK_SERVER | Leave false — the SPA talks to a real backend at VITE_SERVER_URL. (The true in-browser mock mode was removed in 11.) A build-time flag baked into the SPA bundle. |
VITE_SERVER_URL | Backend API URL (empty for same-origin) |
Cloud control plane
The Cloud control-plane distribution lives outside this framework repo. If you deploy a Cloud host on Vercel, remember that Vercel functions have an ephemeral, read-only filesystem — local SQLite and local-FS storage will not persist between invocations. Use a durable database and S3-compatible object storage for artifacts.
| Variable | Required | Description |
|---|---|---|
OS_AUTH_SECRET | yes | ≥ 32 chars (AUTH_SECRET is accepted as a deprecated alias) |
OS_CONTROL_DATABASE_URL | yes | libsql://… (Turso) — control plane DB |
OS_CONTROL_DATABASE_AUTH_TOKEN | yes | Turso token (or TURSO_AUTH_TOKEN) |
OS_STORAGE_ADAPTER | yes | s3 (must, on Vercel) |
OS_S3_BUCKET | yes (s3) | Bucket name |
OS_S3_REGION | yes (s3) | us-east-1, or auto for Cloudflare R2 |
OS_S3_ENDPOINT | optional | For R2 / MinIO / B2 / non-AWS |
OS_S3_ACCESS_KEY_ID | optional | Falls back to AWS SDK credential chain |
OS_S3_SECRET_ACCESS_KEY | optional | Falls back to AWS SDK credential chain |
OS_S3_FORCE_PATH_STYLE | optional | 1 for MinIO / self-hosted |
The Cloud control plane's storage backend (S3, Cloudflare R2, MinIO, etc.) is configured and documented in that separate distribution, not in this framework repo. See Publish, Versioning & Preview for the package publish/install workflow the control plane exposes to the CLI.
Never commit secrets. Use Vercel's environment variable UI or the Vercel CLI (vercel env add) to configure tokens and S3 credentials.
Deployment Checklist
-
api/index.tsHono entrypoint exists withhandle(app)export -
api/_kernel.tsboots the kernel with the correct driver -
vercel.jsonsetsVITE_USE_MOCK_SERVER=falseandVITE_SERVER_URL=(empty) - Rewrite rule routes
/api/*to/apiand excludes/api/from SPA rewrite -
OS_DATABASE_URLis configured in Vercel environment variables (for production drivers) - CORS is configured if frontend and API are on different origins
Related
- Plugin System — the Hono server adapter
- Client SDK — Frontend data fetching
- Driver Configuration — Database setup
- Architecture — Kernel and runtime overview