| title | Deploy to Vercel |
|---|---|
| description | Deploy ObjectStack applications to Vercel with the Hono server adapter. |
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).
In Server mode, ObjectStack runs inside Vercel Serverless Functions. API requests are handled by real backend logic with a real database.
┌─── Vercel ────────────────────────────────────────────────────┐
│ │
│ Static Assets (React SPA) │
│ ┌───────────────────────────────────┐ │
│ │ /index.html, /assets/* │ │
│ └───────────────────────────────────┘ │
│ │
│ Serverless Functions │
│ ┌───────────────────────────────────┐ │
│ │ /api/[...objectstack] │ │
│ │ → ObjectKernel │ │
│ │ → ObjectQL │ │
│ │ → PostgreSQL / MongoDB / ... │──── External DB │
│ └───────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────┘
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.
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;
}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" }
]
}Configure these in Vercel Project Settings → Environment Variables:
| 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) |
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 |
**Never commit secrets.** Use Vercel's environment variable UI or the Vercel CLI (`vercel env add`) to configure tokens and S3 credentials.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.
- [ ]
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
- Plugin System — the Hono server adapter
- Client SDK — Frontend data fetching
- Driver Configuration — Database setup
- Architecture — Kernel and runtime overview