ObjectStackObjectStack

Environment Variables

Canonical list of OS_* environment variables read by the ObjectStack runtime, CLI, and built-in plugins.

Environment Variables

All ObjectStack-owned environment variables use the OS_ prefix. Variables are read at startup unless noted otherwise. Boolean variables accept true / false (case-insensitive); flag-style variables also accept 1 / 0 where noted.

Legacy names. Pre-1.0 unprefixed names (PORT, DATABASE_URL, BETTER_AUTH_SECRET, …) still work this release and emit a one-shot deprecation warning. See Legacy aliases at the bottom of this page. Industry-standard third-party names (NODE_ENV, HOME, OPENAI_API_KEY, TURSO_*, OAuth *_CLIENT_ID / *_CLIENT_SECRET, RESEND_API_KEY, POSTMARK_TOKEN, AI_GATEWAY_*, SMTP_*) are not renamed and are read as-is by their respective libraries.


Runtime & Server

VariableTypeDefaultDescription
OS_PORTnumber3000HTTP listener port for os serve / os dev / os start. Resolution: --portOS_PORTPORT3000.
OS_HOMEpath$HOME/.objectstackObjectStack config / state directory.
OS_MODEenumstandaloneRuntime mode. standalone | cloud.
OS_BOOT_EMPTYflag0When 1, boot the kernel with no metadata artifact (CLI internal).
OS_MIGRATE_AND_EXITflag0When 1, run pending migrations and exit (suitable for one-shot jobs).
OS_DISABLE_CONSOLEflag0When 1, do not mount the Console portal under /_console.
OS_EAGER_SCHEMASflag0When 1, evaluate all lazily-built Zod spec schemas eagerly at module load instead of on first use — an emergency rollback of the lazy-schema memory optimization (higher startup RSS).
OS_SKIP_SCHEMA_SYNCflag0When 1, skip the implicit db:sync on boot. Use after running migrations manually.

Port conflicts behave differently by mode. In dev (os dev, or NODE_ENV=development) a busy port auto-hops to the next free one (up to +100) and the banner prints the actual bound port. In production (os start) a busy port is a hard error (exit 1) — it never silently drifts, because a shifted port breaks reverse-proxy upstreams, OS_AUTH_URL callbacks, and OS_TRUSTED_ORIGINS (CORS). Pin the port explicitly in production (OS_PORT=8080 os start) and keep OS_AUTH_URL / OS_TRUSTED_ORIGINS in sync with it.


Database & Storage

VariableTypeDefaultDescription
OS_DATABASE_URLurlDatabase connection string (e.g. file:./data.sqlite, postgres://…, mongodb://…, memory://). libsql:// / *.turso.io (Turso) is inferred too, but its driver is an optional package: npm install @objectstack/driver-turso, otherwise the boot fails loudly with that command — it never falls back to SQLite.
OS_DATABASE_AUTH_TOKENstringAuth token for a libSQL/Turso connection (--database-auth-token). The vendor's own TURSO_AUTH_TOKEN is read as a fallback and is not renamed (see the third-party names note above). Ignored by every other driver — their credentials live in the URL.
OS_DATABASE_DRIVERenuminferredForce a specific driver when the URL is ambiguous. memory | sqlite | sqlite-wasm | postgres | mysql | mongodb | turso.
OS_DATABASE_SQLITE_JOURNAL_MODEenumwalJournal mode for file-backed SQLite. wal (default) lets a dev server and CLI commands share one file without blocking each other, and is what makes the os migrate occupancy check reliable. Set to delete for SQLite's rollback journal — required when the database lives on a network filesystem (NFS/SMB), where WAL cannot work. The setting is applied, not merely skipped: delete converts a database that already adopted WAL back. Ignored for :memory:, for the WASM SQLite driver, and for non-SQLite drivers. A per-datasource sqliteJournalMode in driver config outranks it. See Journal mode.
OS_ALLOW_DRIVER_CONNECT_FAILUREbooleanfalseEscape hatch for the driver-connect boot guard. By default a data driver that fails to connect at startup refuses the boot — a server that cannot reach its database must not report itself started and then fail every request. The same guard covers a declared datasource that objects bind to via datasource: '…', or an external one with validation.onMismatch: 'fail': those objects have no fallback datasource, so an unconnected one means they are all dead. Set to 1 to boot anyway, in an explicitly degraded state logged loudly at startup. There is no reconnection: whatever failed stays dead for the process lifetime and every query and schema sync routed to it fails.
OS_STORAGE_LOCAL_ROOTpath./.objectstack/data/uploadsRoot directory for the local file storage adapter, relative to the process cwd (used by os serve's default storage capability wiring). This is the same value as Setup → Settings → File Storage → Root directory; setting it here pins that field (it shows as locked-by-env). Renamed from OS_STORAGE_ROOT — see below.
OS_STORAGE_ROOTpathDeprecated alias for OS_STORAGE_LOCAL_ROOT. Still read for one release, with a startup warning; it will be removed in a future major. Rename it now. Before the rename the two halves of the platform spelled this value differently — the CLI wrote OS_STORAGE_ROOT while the settings service read OS_STORAGE_LOCAL_ROOT — so any value other than the default was silently discarded at startup and uploads landed in ./.objectstack/data/uploads regardless. If you set OS_STORAGE_ROOT on an older release, check where your uploads actually are before assuming a backup covered them.
OS_ARTIFACT_PATHpathPath or http(s):// URL to a compiled objectstack.json artifact to boot the kernel from.

Secrets & Clustering

VariableTypeDefaultDescription
OS_SECRET_KEYstring32-byte master key (64 hex chars or base64) for sys_secret encryption — encrypted settings, secret fields, datasource credentials. Required for containerized or multi-node deployments; on a single durable host os start mints and persists a dev key instead. See Deployment Modes.
OS_DEV_CRYPTO_KEYstringDevelopment convenience crypto key, consulted after OS_SECRET_KEY. Do not use in production.
OS_CLUSTER_DRIVERstringmemoryCluster coordination driver id. When set to anything other than memory, the runtime treats the deployment as multi-node (and requires OS_SECRET_KEY). Non-memory drivers are opt-in sibling packages (e.g. redis via @objectstack/service-cluster-redis) — see Cluster.
OS_REDIS_URLurlConnection URL passed to a non-memory cluster driver (e.g. OS_CLUSTER_DRIVER=redis).

Authentication

VariableTypeDefaultDescription
OS_AUTH_URLurlhttp://localhost:<OS_PORT>Public base URL of the auth server. Required behind a proxy or in production.
OS_AUTH_SECRETstringauto-generated (dev)Secret used to sign sessions and cookies. Required in production.
OS_AUTH_TWO_FACTORbooleanfalseEnable the low-level better-auth two-factor plugin. Keep disabled unless your UI handles enrollment, login challenge, and backup-code recovery.
OS_DISABLE_SIGNUPbooleanfalseWhen true, block new email/password sign-ups. The very first user can still sign up to bootstrap admin.
OS_AUTH_EMAIL_PASSWORD_ENABLEDbooleansettings defaultSettings env override for auth.email_password_enabled. Controls local email/password login.
OS_AUTH_SIGNUP_ENABLEDbooleansettings defaultSettings env override for auth.signup_enabled. Takes precedence over UI settings and is preferred over OS_DISABLE_SIGNUP.
OS_AUTH_REQUIRE_EMAIL_VERIFICATIONbooleansettings defaultSettings env override for auth.require_email_verification.
OS_AUTH_MEMBERSHIP_POLICYauto | invite-onlyautoSettings env override for auth.membership_policy — what a newly created user joins (ADR-0093 D1). auto binds every new user to the deployment's default organization. invite-only grants membership solely through an explicit act: creating a workspace, accepting an invitation, an admin adding them, or SSO just-in-time provisioning. Applies to sign-up and to the backfill of pre-existing member-less users. An unrecognized value is rejected with an error log and ignored — the deployment keeps its current policy rather than silently reverting to auto.
OS_AUTH_GOOGLE_ENABLEDbooleansettings defaultSettings env override for auth.google_enabled. Requires Google OAuth credentials from Settings or env.
GOOGLE_CLIENT_IDstringDeployment-level Google OAuth client id for the open-source Google login implementation.
GOOGLE_CLIENT_SECRETstringDeployment-level Google OAuth client secret for the open-source Google login implementation.
OS_TENANCY_POSTUREsingle | group | isolatedderived from OS_MULTI_ORG_ENABLEDWhich organization wall the authorization kernel enforces (ADR-0105 D1). single = no wall. group = organization_id IN accessible_org_ids — organizations are membership boundaries over one shared dataset, with union read access across every organization the caller belongs to. isolated = organization_id = <active organization>, the hard legal-entity wall (formerly spelled multi). Unset derives from OS_MULTI_ORG_ENABLED (trueisolated, else single), so existing deployments are unchanged. An unrecognized value refuses to boot rather than silently falling back to a posture with no wall. Both walled postures require the enterprise @objectstack/organizations runtime — without it the request resolves to single and boot is refused unless OS_ALLOW_DEGRADED_TENANCY=1.
OS_MULTI_ORG_ENABLEDbooleanfalseSuperseded by OS_TENANCY_POSTURE, and still honoured: true selects the isolated posture. When true, organization creation/switching UI is exposed.
OS_OIDC_PROVIDER_ENABLEDbooleantracks MCPWhen true, expose this instance as an OIDC identity provider. When unset it follows the MCP server surface (OS_MCP_SERVER_ENABLED, on by default) — the MCP human-client track is OAuth 2.1, so every MCP-enabled deployment is its own authorization server.
OS_COOKIE_DOMAINstringCookie domain for cross-subdomain session sharing (e.g. .example.com).
OS_TRUSTED_ORIGINScsvComma-separated list of origins permitted for auth callbacks / CSRF.
OS_TERMS_URLurlURL shown next to the "Terms of Service" link on the sign-up form. Empty string hides the link.
OS_PRIVACY_URLurlURL shown next to the "Privacy Policy" link on the sign-up form. Empty string hides the link.

Auth settings precedence:

  1. Environment variables win over values saved in the Setup UI.
  2. OS_AUTH_<SETTING_KEY> settings env vars are the canonical form for settings-backed auth controls.
  3. Existing deployment toggles such as OS_AUTH_TWO_FACTOR and OS_DISABLE_SIGNUP remain supported.
  4. Google credentials can be saved in Setup → Authentication. google_client_secret is encrypted at rest.
  5. GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET remain supported for deployment-level Google OAuth configuration.

CORS

VariableTypeDefaultDescription
OS_CORS_ENABLEDbooleantrueEnable CORS middleware.
OS_CORS_ORIGINcsv*Allowed origins (comma-separated, or *).
OS_CORS_CREDENTIALSbooleantrueAllow credentialed cross-origin requests.
OS_CORS_MAX_AGEnumber86400Preflight cache TTL in seconds.

Branding (single-tenant)

VariableTypeDefaultDescription
OS_PRODUCT_NAMEstringObjectStackProduct name shown in the UI chrome and emails.
OS_PRODUCT_SHORT_NAMEstringOSShort name used in compact UI surfaces (favicons, mobile titles).
OS_APP_NAMEstringApplication name surfaced to auth providers (used as the OAuth app display name).

Email

VariableTypeDefaultDescription
OS_EMAIL_PROVIDERenumlogTransport. log | smtp | resend | postmark. log (default) prints to stdout without sending — it is also how a deployment declares that it does not send mail. Any other value is a delivery intent, and a boot that cannot honour it fails loudly instead of substituting the log transport.
OS_EMAIL_API_KEYstringAPI key for resend / postmark. Required when either is selected — a boot without it fails rather than starting with a transport that records every message in sys_email as sent and delivers nothing. Set OS_EMAIL_PROVIDER=log for environments that should not send mail.
OS_EMAIL_FROMemailDefault From: address.
OS_EMAIL_RETRIESnumber0Retry count for transient send failures (0 = no retry).
OS_EMAIL_SMTP_HOSTstringSMTP server hostname. Required when OS_EMAIL_PROVIDER=smtp — a boot without it fails loudly rather than starting with a transport that logs mail instead of sending it.
OS_EMAIL_SMTP_PORTnumber587SMTP port. 465 selects implicit TLS (SMTPS).
OS_EMAIL_SMTP_SECUREbooleantrueRequire TLS. On port 465 that means implicit TLS; on any other port a required STARTTLS upgrade (a server that will not upgrade fails the send instead of leaking credentials in the clear). false connects in the clear and upgrades only when STARTTLS is offered.
OS_EMAIL_SMTP_USERstringSMTP AUTH username. Omit for servers that accept unauthenticated relay.
OS_EMAIL_SMTP_PASSWORDstringSMTP AUTH password.

SMTP delivery ships in @objectstack/plugin-email (ADR-0012) and is implemented with nodemailer, imported lazily so deployments that never select SMTP — and non-Node runtimes — never load node:net / node:tls. Any provider that speaks SMTP works through it: a corporate mail server, Aliyun DirectMail, Tencent SES, QQ / 163 enterprise mailboxes.

These variables configure the transport at boot. The same connection can be configured at runtime in Settings → Mail (namespace mail, keys smtp_host / smtp_port / smtp_secure / smtp_user / smtp_password), which hot-swaps the live transport without a restart and whose Send test email button performs a real delivery. Settings-page values are overridden by the namespace's own OS_MAIL_* env door (e.g. OS_MAIL_SMTP_HOST), which locks the field in the UI.


AI

These variables configure the ObjectOS in-product AI runtime, which is not part of the open-source framework. The open-source framework has no in-UI AI runtime to configure: it exposes AI through @objectstack/mcp (BYO-AI), where the model and provider are configured in your own MCP client (Claude, Cursor, a local model, …). See the AI Capabilities guide.

VariableTypeDefaultDescription
AI_GATEWAY_MODELstringVercel AI Gateway model id (for example openai/gpt-4.1-mini or anthropic/claude-sonnet-4-5). When set, the AI service boots with the gateway adapter before trying direct providers.
AI_GATEWAY_API_KEYstringVercel AI Gateway API key. Required by the gateway SDK for real gateway calls; by itself it does not select the gateway adapter. Pair it with AI_GATEWAY_MODEL.
OPENAI_API_KEYstringSelects the direct OpenAI adapter when no gateway model is configured. Default model: gpt-4o.
ANTHROPIC_API_KEYstringSelects the direct Anthropic adapter when gateway and OpenAI are not configured. Default model: claude-sonnet-4-20250514.
GOOGLE_GENERATIVE_AI_API_KEYstringSelects the direct Google Gemini adapter when gateway, OpenAI, and Anthropic are not configured. Default model: gemini-2.0-flash.
OS_AI_MODELstringprovider defaultOverrides the model id for direct OpenAI / Anthropic / Google provider detection. Does not override AI_GATEWAY_MODEL; gateway model ids already include the provider prefix.
OS_AI_ACTION_API_BASE_URLurlBase URL prepended to relative type: 'api' action targets exposed as AI tools. Without this or a plugin apiActionBaseUrl, relative API actions are skipped for AI exposure.
OS_AI_PROVIDERenumSettings override for the AI provider. Supported values include gateway, openai, anthropic, google, deepseek, dashscope, cloudflare, siliconflow, and openrouter. When set, it locks the Settings UI value.
OS_AI_GATEWAY_MODELstringSettings override for the Vercel AI Gateway model id. Use with OS_AI_PROVIDER=gateway.
OS_AI_GATEWAY_API_KEYstringSettings override for the Vercel AI Gateway API key. Use with OS_AI_PROVIDER=gateway.
OS_AI_OPENAI_BASE_URLurlSettings override for the OpenAI-compatible chat base URL. Use with OS_AI_PROVIDER=openai for Azure, local gateways, or third-party OpenAI-shaped APIs.
OS_AI_OPENAI_API_KEYstringSettings override for the OpenAI-compatible API key. Stored only in env; the Settings UI cannot overwrite it while present.
OS_AI_OPENAI_MODELstringgpt-4oSettings override for the OpenAI-compatible chat model id.
OS_AI_ANTHROPIC_API_KEYstringSettings override for the Anthropic API key. Use with OS_AI_PROVIDER=anthropic.
OS_AI_ANTHROPIC_MODELstringclaude-sonnet-4-20250514Settings override for the Anthropic model id.
OS_AI_GOOGLE_API_KEYstringSettings override for the Google Generative AI API key. Use with OS_AI_PROVIDER=google.
OS_AI_GOOGLE_MODELstringgemini-2.0-flashSettings override for the Google model id.
OS_AI_<PROVIDER>_API_KEYstringSettings override for preset OpenAI-compatible providers, for example OS_AI_DEEPSEEK_API_KEY, OS_AI_DASHSCOPE_API_KEY, OS_AI_SILICONFLOW_API_KEY, or OS_AI_OPENROUTER_API_KEY.
OS_AI_<PROVIDER>_MODELstringprovider defaultSettings override for preset provider model ids, for example OS_AI_DEEPSEEK_MODEL=deepseek-chat.

The boot-time LLM adapter priority is:

  1. Explicit AIServicePlugin({ adapter }) or per-plugin gatewayModel option.
  2. AI_GATEWAY_MODEL using @ai-sdk/gateway.
  3. OPENAI_API_KEY using @ai-sdk/openai.
  4. ANTHROPIC_API_KEY using @ai-sdk/anthropic.
  5. GOOGLE_GENERATIVE_AI_API_KEY using @ai-sdk/google.
  6. MemoryLLMAdapter echo mode when no real provider is configured.

After boot, if the Settings service is mounted, the ObjectOS AI runtime reads the ai Settings namespace and swaps the adapter when the provider comes from env or a stored Settings UI value. The manifest default provider=memory is ignored so it does not mask boot-time auto-detection; an explicit OS_AI_PROVIDER=memory or stored UI value does switch the runtime back to memory. Settings values resolve as:

env (`OS_<NAMESPACE>_<KEY>`) > stored Settings UI value > default

That means OS_AI_PROVIDER=openai plus OS_AI_OPENAI_BASE_URL=... wins over both the Settings UI and the boot-time provider auto-detection. ObjectStack does not read unprefixed settings override names such as AI_PROVIDER or AI_OPENAI_BASE_URL.

For example, a third-party OpenAI-compatible provider can be deployment-locked without using the Settings UI:

OS_AI_PROVIDER=openai
OS_AI_OPENAI_API_KEY=sk-...
OS_AI_OPENAI_MODEL=your-model
OS_AI_OPENAI_BASE_URL=https://your-provider.example.com/v1

Provider credentials keep their upstream names. ObjectStack does not rename OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, or AI_GATEWAY_* to OS_*.

OpenAI-compatible base URLs. Use OS_AI_OPENAI_BASE_URL with OS_AI_PROVIDER=openai, configure the same fields in Settings → AI, or pass an explicit adapter in code. Do not rely on OPENAI_BASE_URL as a platform-level environment variable.


MCP Server

Enable this to make the app you built AI-operable: with the MCP server on, an MCP client — Claude Code, Claude Desktop, Cursor, or a local model — connects to your running app and gets a generated tool surface over your objects and actions (query_records, run_action, …), bound to the caller's principal and governed by the same RBAC / RLS as the Console. No custom tooling, no separate API. See Actions as Tools for the tool set.

The HTTP surface and the long-lived stdio transport are separate switches (they used to share one, which let =true silently attach an unscoped transport — see the note below):

os start                                                  # HTTP MCP served at /api/v1/mcp by default
OS_MCP_SERVER_ENABLED=false os start                      # opt out of the HTTP MCP surface
OS_MCP_STDIO_ENABLED=true OS_MCP_STDIO_API_KEY=osk_... os start   # start the local stdio transport as that key's identity
VariableTypeDefaultDescription
OS_MCP_SERVER_ENABLEDbooleantrueThe MCP HTTP surface (/api/v1/mcp) is a core capability and defaults on. Set false to disable it (endpoint 404s, the Connect-an-Agent page disappears).
OS_MCP_STDIO_ENABLEDbooleanfalseAuto-start the long-lived stdio transport at boot. Opt-in and stricter than the HTTP surface. Requires OS_MCP_STDIO_API_KEY — stdio runs as that key's identity with RLS/FLS/tenant applied; if the key is missing or invalid, boot fails closed (stdio refuses to start). See ADR-0101.
OS_MCP_STDIO_API_KEYstringThe osk_... API key the stdio transport runs as. Resolved through the same verify chain as the HTTP/REST surfaces, so reads are scoped to that identity's permissions. Mint one from Setup → Connect an Agent (or POST /api/v1/keys). For full authority, mint a key on a platform-admin or dedicated service identity — there is deliberately no system/unscoped bypass.
OS_MCP_SERVER_NAMEstringobjectstackServer name advertised to MCP clients.
OS_MCP_SERVER_TRANSPORTenumstdiostdio | http. Use http (Streamable HTTP) for a remote client; stdio for a local one.

Deprecated (one release): OS_MCP_SERVER_ENABLED=true also used to auto-start the stdio transport — overloading the HTTP switch, so setting it to "make sure MCP is on" silently attached the unscoped stdio bridge. That trigger still works but now logs a deprecation warning; use OS_MCP_STDIO_ENABLED=true instead. OS_MCP_SERVER_ENABLED=false only ever gated HTTP and is unaffected.


Pinyin recall for $search (ADR-0098): with the switch on, every object's display/name field gets a hidden, platform-maintained companion column storing full pinyin + initials ("张伟" → "zhangwei zw"), so lookup pickers, list quick-search and ⌘K match zhangwei / zw against CJK names — transparently, with no client or object changes.

os start                                  # auto-on when the stack's i18n config lists any zh-* locale
OS_SEARCH_PINYIN_ENABLED=true os start    # force on regardless of locales
OS_SEARCH_PINYIN_ENABLED=false os start   # force off (e.g. a zh-locale stack that doesn't want the extra column)
VariableTypeDefaultDescription
OS_SEARCH_PINYIN_ENABLEDbooleanlocale-derivedPinyin search recall. When unset, the default derives from the stack's configured locales (i18n.defaultLocale / supportedLocales / fallbackLocale): any zh-* locale turns it on; an explicit value always wins. Gates both the compile-time __search companion column and the plugin-pinyin-search populate hooks, so there is no half-state. Off ⇒ no extra column, and pinyin-pro is never loaded.

Coverage includes sys_user — the people picker finds users by pinyin with no per-object configuration. Rows that predate the switch are backfilled automatically on the first boot after it turns on (paged, idempotent); for runtime bulk imports that bypassed write hooks, rebuildSearchCompanion (from @objectstack/plugin-pinyin-search) recomputes the column on demand. See Queries → Pinyin recall.


Marketplace & Metadata

VariableTypeDefaultDescription
OS_MARKETPLACE_CACHEenumonoff disables the in-memory marketplace listing cache.
OS_MARKETPLACE_PUBLIC_BASE_URLurlPublic base URL of the marketplace registry (proxied from this runtime when set).
OS_ALLOW_UNMASKED_OBJECT_METADATAbooleanfalseEscape hatch for the metadata-plane field-level security mask (ADR-0106 D8). By default every object schema served by /meta and /metadata is projected onto the fields the calling user may read, so a field they cannot read does not appear at all — not its name, label, type, picklist options, formula, visibleWhen predicate, defaultValue, or the requiredPermissions capability guarding it. Set to 1 to serve the full schema to every authenticated caller, as releases before this one did. This changes disclosure only: the data plane still masks values and refuses forbidden writes either way, and the console reads field affordances from /auth/me/permissions, so toggling it never changes UI correctness. The REST layer also honours a per-server metadata.maskObjectFields: false; this variable is the deployment-wide knob and covers the runtime /metadata dispatcher, which has no REST config to read.
OS_METADATA_WRITABLEcsv— (none)Comma-separated metadata type names (e.g. hook,validation) granted a runtime escape hatch that treats them as allowOrgOverride: true, letting artifact-backed items of those protected types be overridden per-org outside their static registry declaration. See ADR-0005.

Multi-tenant / Cloud control plane

These variables are only meaningful when running in OS_MODE=cloud or against the hosted ObjectOS Cloud control plane.

VariableTypeDefaultDescription
OS_BASE_URLurlPublic base URL of this runtime, used in generated webhooks and links.
OS_ROOT_DOMAINstringRoot domain for multi-tenant subdomain routing (e.g. example.com).
OS_ORGANIZATION_IDstringPin the runtime to a single organization id (per-process scope).
OS_ENVIRONMENT_IDstringPin the runtime to a single environment id (per-process scope).
OS_CLOUD_URLurlhttps://cloud.objectos.aiBase URL of the cloud control plane the CLI / runtime talks to. Set to off / local / none / disabled to disable cloud.
OS_CLOUD_API_KEYstringShared secret authenticating runtime → cloud SSO handoffs.
OS_CLI_CLIENT_IDstringOAuth client id used by os login.
OS_TOKENstringPersonal access token used by the CLI in non-interactive contexts (CI).
OS_PLATFORM_SSObooleantrueWhen false, fall back to local auth instead of the platform SSO handshake.
OS_PROVISION_SYNCflag0When 1, force synchronous provisioning of artifact kernels (slower boot, deterministic).
OS_RUNTIME_PORTnumberPort the cloud control plane uses to reach this runtime (distinct from public OS_PORT).
OS_PREVIEW_MODEenumPreview deployment routing mode.
OS_PREVIEW_BASE_DOMAINScsvComma-separated base domains used to resolve preview hostnames.

Observability

VariableTypeDefaultDescription
OS_OBS_EXPORTERenumnoopOpenTelemetry exporter. noop | console | json | otlp. noop (default) imposes no runtime cost.
OS_OBS_SERVICE_NAMEstringobjectstackservice.name resource attribute.
OS_OBS_DEPLOYMENT_ENVstringproductiondeployment.environment resource attribute.
OS_OTLP_ENDPOINTurlOTLP/HTTP collector endpoint. Required when OS_OBS_EXPORTER=otlp.
OS_OTLP_HEADERScsvComma-separated key=value pairs added to every OTLP export.
OS_OTLP_FLUSH_MSnumber10000OTLP batch flush interval.

Tuning (advanced)

VariableTypeDefaultDescription
OS_KERNEL_CACHE_SIZEnumber32Max in-memory artifact kernels per process (cloud mode).
OS_KERNEL_TTL_MSnumber900000Idle TTL for cached kernels in ms.
OS_ENV_CACHE_TTL_MSnumber300000Env-record cache TTL in ms.
OS_ARTIFACT_CACHE_TTL_MSnumber300000Artifact-record cache TTL in ms.
OS_ARTIFACT_FETCH_TIMEOUT_MSnumber60000Timeout for remote artifact fetches. Only a positive value is honored — an unset, non-numeric, or 0 value falls back to the 60s default (pass fetchTimeoutMs: 0 in artifactSource config to actually disable the timeout).
OS_SANDBOX_HOOK_TIMEOUT_MSnumber250Default CPU-time budget for a sandboxed hook body (QuickJS, ADR-0102): how much VM-active time a body may burn — idle host-await time and a nested hook's own run are NOT charged. A loaded/slow host rarely needs to raise this now (it is not wall-clock), but the knob remains. Only a positive integer is honored; unset / non-numeric / non-positive keeps the 250ms default. A hook body's own declared timeoutMs still wins over this.
OS_SANDBOX_ACTION_TIMEOUT_MSnumber5000Default CPU-time budget for a sandboxed action body (QuickJS). Same resolution rules as the hook variant above (positive integer only; an action body's own timeoutMs still wins).
OS_SANDBOX_WALL_CEILING_MSnumber30000Wall-clock ceiling (ADR-0102) — the backstop that cuts a hook/action body stuck on a host call that never settles (which burns no CPU, so the CPU budget alone would never fire). The effective ceiling is max(this, cpuBudget), so it can never cut a body still inside its CPU budget. Positive integer only; unset keeps 30s.
OS_INLINE_SEED_BUDGET_MSnumber8000Time budget for synchronous seed execution at boot before deferring to a worker.
OS_TENANT_AUDITflag1Set to 0 to silence the tenant-isolation audit warnings emitted by the SQL driver.

Legacy aliases

Some env vars accept a legacy alias for compatibility. Ecosystem-standard names (e.g. DATABASE_URL, AUTH_SECRET, BETTER_AUTH_*, PORT, CORS_*, MCP_SERVER_*) are permanently accepted and no longer warn. ObjectStack's own former names are deprecated — prefer the canonical OS_*.

Removed in 11 (rename required): OS_MULTI_TENANTOS_MULTI_ORG_ENABLED, AUTH_BASE_URL/OS_AUTH_BASE_URLOS_AUTH_URL.

CanonicalLegacy
OS_PORTPORT
OS_DATABASE_URLDATABASE_URL
OS_AUTH_URLBETTER_AUTH_URL
OS_AUTH_SECRETBETTER_AUTH_SECRET, AUTH_SECRET
OS_ROOT_DOMAINROOT_DOMAIN
OS_CORS_ENABLEDCORS_ENABLED
OS_CORS_ORIGINCORS_ORIGIN
OS_CORS_CREDENTIALSCORS_CREDENTIALS
OS_CORS_MAX_AGECORS_MAX_AGE
OS_AI_MODELAI_MODEL
OS_MCP_SERVER_ENABLEDMCP_SERVER_ENABLED
OS_MCP_SERVER_NAMEMCP_SERVER_NAME
OS_MCP_SERVER_TRANSPORTMCP_SERVER_TRANSPORT
OS_METADATA_WRITABLEOBJECTSTACK_METADATA_WRITABLE
OS_HOMEOBJECTSTACK_HOME
OS_DEV_CRYPTO_KEYOBJECTSTACK_DEV_CRYPTO_KEY

On this page