Quickstart

Install the CLI, sign in, create an app, and deploy it. About five minutes from nothing to a live URL.

From nothing to a deployed app in about five minutes.

1. Install the CLI

npm install -g railcode@latest      # or: pnpm add -g railcode@latest
railcode --version

The CLI owns the build for every template. Your app never declares a bundler or a backend build script.

2. Sign in

railcode login

Login is browser-based. The CLI starts a localhost callback, prints an authorization link, and opens your browser. You approve the CLI from the dashboard. The CLI then exchanges a one-time code for a long-lived, revocable personal API token and saves it to ~/.railcode/config.json.

On a headless or SSH machine, use railcode login --paste (alias --no-browser) and paste the one-time code that the authorize page shows.

If you do not have an organization yet, finish onboarding in the dashboard and run railcode login again. Deploying needs an org on file.

3. Create an app

railcode init my-app
cd my-app
npm install

The slug must be a DNS label: ^[a-z0-9][a-z0-9-]{0,62}$.

Four templates are available with --template:

TemplateFrontendBackend function
hono+vite (default)Vite + ReactHono
hono+staticone index.html, no buildHono
tanstackTanStack Start (SPA mode)server functions + /api/*
staticstatic filesnone, pure hosting

Each template with a backend function includes a small platform tour: identity, a todo list on the key/value store, files, and the read-only org surfaces. Read it, then delete it. It is scaffolding, not a style guide.

4. Run it locally

railcode dev

This serves the frontend and the backend function. It routes the same paths that production routes (/api/*, /_serverFn/*). The backend function talks to a local data plane with the same wire format as production. So "works in railcode dev" means "works deployed."

Storage is a local scratch store (--reset clears it). It never touches live data. Governed capabilities (SQL, saved queries, LLM, email, connectors, agents) go to your real instance under a dev token that carries your identity. They hit real providers and real spend.

5. Write a route

The backend function is the only thing that touches the platform. A route looks like this:

import { Hono } from "hono";
import { ctx, db } from "@railcode/sdk";

const app = new Hono();

app.get("/api/me", (c) => c.json({ user: ctx.user }));

app.post("/api/notes", async (c) => {
  const { title } = await c.req.json();
  const id = crypto.randomUUID();
  await db.collection("notes").put(`${ctx.user!.id}:${id}`, {
    id,
    owner: ctx.user!.id,      // store the owner, don't trust the request body
    title,
    created_at: new Date().toISOString(),
  });
  return c.json({ id }, 201);
});

export default app;

The frontend calls fetch('/api/notes'). It never sees a platform endpoint.

6. Declare what the app may do

Write a manifest.yaml beside railcode.json. On apps v2 run_as: app is mandatory: the backend function is the app's principal.

run_as: app
llm: true
saved_queries:
  - revenue_by_month

Declare only what the backend function uses, then check it:

railcode manifest validate

7. Deploy

railcode deploy

This runs the CLI-owned build, uploads the static files and the backend function as one unit, ratifies the manifest, and prints the live URL, https://<app>.<org>.<serving-domain>/.

A new app defaults to organization access: every member of your org can open it. Use railcode deploy --private for a private first deploy.

Then what

  • Confirm it works: open the URL, check that /api/* calls succeed, and read the backend's own record of what happened with railcode logs app --app <slug>.
  • Seed some data so the UI is not all empty states: railcode app kv set notes demo '{"title":"Hello"}'.
  • Read the app model for the shape of everything else, and limits for what the platform deliberately does not do.

Start from an example

For anything past the scaffolded tour, read Railcode-HQ/railcode-examples. Every app there is apps v2 (a static frontend/ plus a server/index.ts backend function), so it is safe to copy from.

ExampleRead it for
apps/kanbanThe plainest app: a shared store and one asymmetric rule, written where a caller cannot reach it
apps/chatAn agent loop that streams ndjson to the page, and per-user isolation built from keys plus an owner check
apps/crmA large legacy app ported through one module
agents/pitch-deckStarting an agent run from a backend function and polling it
agents/proposalsWhy a schedule belongs to the agent, not the app

Copy one directory as plain files:

mkdir my-app && curl -fsSL \
  https://github.com/Railcode-HQ/railcode-examples/archive/refs/heads/main.tar.gz \
  | tar -xz --strip-components=3 -C my-app railcode-examples-main/apps/kanban

Then set app in railcode.json to your own slug.

On this page