SDKs & integrations

CLI

The orbitnest CLI signs you in, links a directory to a project, runs SQL migrations, checks schema drift, generates TypeScript types and manages webhooks and SMS.

The orbitnest CLI brings the day-to-day backend workflow into your terminal and your repo. Sign in once, link a directory to a project, then run versioned SQL migrations, ad-hoc SQL, schema drift checks and type generation against that project.

Install

The CLI is published to npm as @orbitneststudio/cli and installs a binary named orbitnest. It requires Node.js 18 or later. This page describes version 0.6.0, which isn't on npm yet. Behavior that is new in 0.6.0 is marked "from version 0.6.0".

Terminal
npm install -g @orbitneststudio/cli
orbitnest --help

Or run it without installing:

Terminal
npx @orbitneststudio/cli --help

Quickstart

Terminal
# 1. Sign in (stores tokens in ~/.orbitnest/credentials.json)
orbitnest login

# 2. Link this directory to a project (writes .orbitnest/config.json)
orbitnest link my-app

# 3. Scaffold a migration, edit it, then apply it
orbitnest migration new "create posts table"
orbitnest db push

# 4. Generate TypeScript types from the live schema
orbitnest gen types

Authentication

Sign in

Terminal
orbitnest login

login signs in with your OrbitNest admin email and password. It reads each value from the first source that has one:

ValueFlagEnvironment variableFallback
Email--email, -eORBITNEST_EMAILInteractive prompt
Password--passwordORBITNEST_PASSWORDMasked interactive prompt
Two-factor code--codeORBITNEST_MFA_CODEInteractive prompt
API URL--urlORBITNEST_API_URLhttps://api.orbitnest.io

Without a TTY (for example in CI), the password and two-factor code cannot be prompted for, so pass them as flags or environment variables.

If your account has two-factor authentication turned on, the first sign-in step returns a challenge and the CLI asks for a code. Enter the 6-digit code from your authenticator app or one of your recovery codes.

Terminal
ORBITNEST_EMAIL=you@example.com \
ORBITNEST_PASSWORD="$ORBITNEST_PASSWORD" \
ORBITNEST_MFA_CODE=123456 \
orbitnest login

Email and password only

The CLI has no browser-based Google, GitHub or Apple sign-in. If you use the MCP server, its orbitnest_login tool supports those providers and writes the same credentials file, so the CLI can use that session too.

Tokens and sessions

  • Tokens are stored in ~/.orbitnest/credentials.json with file mode 0600, in a ~/.orbitnest directory with mode 0700. The MCP server reads and writes the same file. From version 0.6.0, the file is written atomically (a temporary file, then a rename), and its mode is reset to 0600 on every write.
  • When the API rejects an expired access token, the CLI exchanges the stored refresh token for a new one, saves it, and retries the request once. If the refresh fails, the command exits and asks you to run orbitnest login again.
  • Refresh tokens rotate, and reusing an old one revokes the session. From version 0.6.0 (and MCP server 1.4.0), refreshes are serialized through a lock file, ~/.orbitnest/credentials.lock. Before refreshing, the CLI re-reads the credentials file. If another CLI or MCP process has already rotated the token, it uses that token instead of refreshing again. A lock left by a crashed process is ignored after 75 seconds.
  • orbitnest whoami shows the signed-in email, the API URL, and when the access token expires.
  • orbitnest logout revokes the session on the server and clears the local session. The stored API URL is kept. From version 0.6.0, it refreshes an expired access token first so it can revoke the current refresh token, and prints a warning if the revoke fails. Older versions could send an already-rotated token, which revoked nothing.

Linking a project

Most commands act on one project. Link the current directory once:

Terminal
orbitnest projects          # list name, slug and id
orbitnest link my-app       # match by id, slug or name (name match is case-insensitive)

With no argument, link links your only project automatically, or prints the list to choose from if you have more than one. From version 0.6.0, a name that matches more than one project is refused, here and with --project, and the error lists the matching slugs. Use the slug or id instead.

link writes .orbitnest/config.json in the current directory. It contains the project id, slug, name and API URL, no secrets, so you can commit it. The MCP server reads the same file.

.orbitnest/config.json
{
  "projectId": "3f6c1a52-8d0e-4c1b-9a43-1e2f5b7c9d10",
  "projectSlug": "my-app",
  "name": "My App",
  "apiUrl": "https://api.orbitnest.io"
}

The shape is { projectId, projectSlug, name?, apiUrl? }. Versions before 0.6.0 wrote the slug as slug. The CLI and the MCP server still read that key, and from version 0.6.0 the CLI writes projectSlug.

To target a different project for a single command, pass --project (-p) with a project UUID, slug or name:

Terminal
orbitnest db status --project my-other-app

The CLI reads .orbitnest/config.json from the current directory only. It does not search parent directories.

API URL resolution

The API base URL is taken from the first of these that is set:

  1. ORBITNEST_API_URL
  2. apiUrl in .orbitnest/config.json
  3. apiUrl in ~/.orbitnest/credentials.json (saved by login --url)
  4. https://api.orbitnest.io

From version 0.6.0, trailing slashes are removed from the URL, so https://api.example.com/ works.

Migrations

A migration is a plain .sql file in the migrations directory (default migrations/, change it with --dir/-d). The file name must start with a numeric id followed by _ or -, for example 001_create_posts.sql. Files are applied in numeric id order, and ids must be unique. .sql files without a numeric prefix are ignored.

An optional -- migrate:down line splits the file into a forward section and a rollback section. From version 0.6.0, the marker must be the whole line: -- migrate:down, -- down or --- DOWN ---. A comment that only starts with "down", such as -- Down-sampled metrics, no longer splits the file. The Node.js SDK and the MCP server use the same rule.

migrations/001_create_posts_table.sql
-- Migration 001: create posts table
CREATE TABLE posts (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  title text NOT NULL,
  created_at timestamptz DEFAULT now()
);

-- migrate:down
DROP TABLE posts;

orbitnest migration new "<name>" creates the next file (002_<name>.sql, and so on) with both sections stubbed out. It never overwrites an existing file.

CommandWhat it does
orbitnest db pushApplies every migration that has not been applied successfully, in order. Each file's forward section runs as one BEGIN; … COMMIT; batch.
orbitnest db statusLists every migration file as applied, pending, modified or (from version 0.6.0) failed.
orbitnest db rollback [id]Runs the -- migrate:down section of the latest applied migration, or of the given id, then removes it from the registry. Fails if the file has no down section.
orbitnest db reset --yesDrops every table in the public schema except internal tables (names starting with auth_, pg_ or _), then applies all migrations from scratch. From version 0.6.0, it does a dry run first.

How tracking works:

  • Applied migrations are recorded in a migrations table in your project database (migration_id, name, checksum, executed_at, status). The CLI creates it on first use.
  • The checksum is a SHA-256 of the whole file. If an applied file changes, db status marks it modified and db push stops with an error. Add a new migration instead of editing history.
  • If a migration fails, its transaction is rolled back, it is recorded with status failed, and push stops. The next push retries it.
  • The MCP server's migration tools use the same file format and the same migrations table.

db reset deletes data

db reset drops your tables, including the migrations registry, and everything in them. It refuses to run without --yes (or --force). Use it on development projects only.

From version 0.6.0, db reset first sends the whole reset as one script that ends in a rollback: BEGIN;, the drops, every migration's forward section, then ROLLBACK;. If any part fails, nothing is dropped and the command stops with "Reset aborted — nothing was dropped". The API accepts at most 50,000 characters of SQL per call. When the drops plus all migrations are longer than that, the dry run fails and the reset doesn't run.

See Migrations for writing migrations and running them from other tools.

Running SQL

Terminal
orbitnest db sql "select id, title from posts order by created_at desc limit 5"
orbitnest db sql --file scripts/backfill.sql

The result rows are printed as JSON, followed by a row count. SQL runs through the project's admin SQL endpoint (POST /api/projects/:projectId/database/sql), which validates each statement. For example, statements that drop, truncate, alter or DELETE FROM the internal auth_* tables return 403, as does a DO block that loops over the table catalog without excluding them.

Project owner only

The database commands (db push, db status, db rollback, db reset, db sql, db diff and gen types) call the project SQL endpoint, which only the project's creator may use. Other workspace members get 403 This operation is restricted to the project owner. From version 0.6.0, the CLI adds an explanation to that error.

Schema drift

db diff compares the live public schema (tables, columns, types, nullability and defaults) with a snapshot you commit to the repo.

Terminal
# Record the current live schema as the baseline
orbitnest db diff --save        # writes .orbitnest/schema.snapshot.json

# Later: report what changed since the snapshot
orbitnest db diff

db diff prints added, removed and changed tables and columns. It exits with code 1 when it finds drift, so you can fail a CI job on unexpected schema changes. Internal tables (auth_*, pg_*, _*) are skipped.

Type generation

Terminal
orbitnest gen types                      # writes orbitnest.types.ts
orbitnest gen types --out src/db.ts      # custom path (-o)
orbitnest gen types --stdout > types.ts  # print instead of writing

gen types reads information_schema.columns for the public schema, skipping internal tables, and emits one interface per table plus a Database map:

orbitnest.types.ts
// Generated by @orbitneststudio/cli — do not edit by hand.
// Re-run `orbitnest gen types` after schema changes.

export interface Posts {
  id: string;
  title: string;
  created_at: string | null;
}

export interface Database {
  "posts": Posts;
}
  • Nullable columns are typed T | null. From version 0.6.0 they are required properties, because selected rows always include every column. Older versions made them optional (column?: T | null).
  • smallint, integer, real and double precision map to number. From version 0.6.0, bigint (int8), numeric and decimal map to string, because the API returns those values as strings.
  • boolean maps to boolean. Text, uuid, date/time and bytea types map to string. From version 0.6.0, enums (USER-DEFINED) map to string and json/jsonb to unknown.
  • Arrays become T[]. Any other type becomes unknown.

Keep types in sync

Run orbitnest gen types in a predev or prebuild script, or after every db push, and commit the output.

Direct database connection

Terminal
orbitnest db connect

Prints the project's direct Postgres connection string, then the host, port, database, user and sslmode, and a pooled connection string when the server has one configured. Direct connections are turned off unless the OrbitNest deployment enables them. When they are off, the command fails with "Direct database connections are not enabled for this deployment."

Webhooks

Manage database webhooks for the linked project:

Terminal
orbitnest webhooks list
orbitnest webhooks create --url https://example.com/hooks/orbitnest \
  --events INSERT,UPDATE --table posts --name post-changes
orbitnest webhooks test <webhook-id>
orbitnest webhooks delete <webhook-id>
Flag (create)DefaultDescription
--urlrequiredEndpoint that receives the signed POST
--eventsINSERT,UPDATE,DELETEComma-separated row events
--tableall tablesOnly fire for this table
--namewebhookDisplay name

create prints the webhook's signing secret once. Store it right away. test sends a test event and prints the HTTP status your endpoint returned.

SMS (Twilio)

Configure the project's Twilio credentials for SMS OTP sign-in:

Terminal
orbitnest sms get
orbitnest sms set --sid AC0123456789abcdef --token "$TWILIO_AUTH_TOKEN" --from +15555550123 --enable
orbitnest sms test +15555550123

sms set updates only the fields you pass: --sid, --token, --from, and --enable or --disable. The auth token is stored encrypted and is never returned. sms get only shows whether it is set.

Auth security

Read or change the limits for your app's users: code length, code expiry, wrong codes allowed, codes per email per hour, and password lockout.

Terminal
orbitnest auth-security get
orbitnest auth-security set --code-length 6 --max-attempts 3 --lockout-attempts 5 --lockout-minutes 30

set changes only the flags you pass: --code-length (6–8), --code-expiry (minutes, 1–60), --max-attempts (1–10), --codes-per-hour (1–100), --lockout-attempts (1–50) and --lockout-minutes (1–1440). It needs the workspace admin role.

Command reference

CommandDescription
orbitnest loginSign in (--email, --password, --code, --url)
orbitnest logoutRevoke the server session and clear the local session
orbitnest whoamiShow the current session, API URL and token expiry
orbitnest projectsList your projects
orbitnest link [id|slug|name]Link the current directory to a project
orbitnest migration new <name>Scaffold the next migration file
orbitnest db pushApply pending migrations
orbitnest db statusShow applied, pending and modified migrations
orbitnest db rollback [id]Roll back the latest (or given) migration
orbitnest db reset --yesDrop all tables and re-apply every migration
orbitnest db sql "<SQL>"Run SQL (--file <path> to read from a file)
orbitnest db diffReport schema drift against the snapshot (--save to update it)
orbitnest db connectPrint the direct Postgres connection string
orbitnest gen typesGenerate TypeScript types (--out, --stdout)
orbitnest webhooks list|create|delete|testManage database webhooks
orbitnest sms get|set|testManage Twilio SMS settings
orbitnest auth-security get|setRead or change end-user auth limits

Global options

OptionApplies toDescription
-p, --project <id|slug|name>db, gen, webhooks, smsTarget a project instead of the linked one
-d, --dir <path>migration new, db push/status/rollback/resetMigrations directory (default migrations)
-o, --out <file>gen typesOutput file (default orbitnest.types.ts)
--stdoutgen typesPrint to stdout
-f, --file <path>db sqlRead SQL from a file
-h, --helpallShow help
-v, --versionallShow the version

Environment variables

VariablePurpose
ORBITNEST_API_URLAPI base URL, overrides the linked and stored URL
ORBITNEST_EMAIL, ORBITNEST_PASSWORDNon-interactive login
ORBITNEST_MFA_CODETwo-factor code for non-interactive login
NO_COLORTurn off colored output

Files

PathScopeContents
~/.orbitnest/credentials.jsonPer user, mode 0600Access and refresh tokens, API URL, user. Shared with the MCP server. Never commit it.
~/.orbitnest/credentials.lockPer userShort-lived lock held while a token refresh runs (from version 0.6.0). Shared with the MCP server.
.orbitnest/config.jsonPer directory{ projectId, projectSlug, name?, apiUrl? }. Safe to commit.
.orbitnest/schema.snapshot.jsonPer directoryBaseline for db diff. Commit it.
migrations/*.sqlPer directoryYour migrations