Skip to main content

Quickstart

Build and run a complete application in under 5 minutes. By the end, you will have a working task manager with a data table, create/edit forms, and status management.

Prerequisites

1. Write Your First .orb File

Create a file called my-app.orb with the following content:

orbital TaskManager {
entity Task [persistent: tasks] {
id : string!
title : string!
description : string
status : string
}
trait TaskCrud -> Task [interaction] {
initial: Listing
state Listing {
INIT -> Listing
(fetch Task)
(render-ui main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "EDIT", label: "Edit" }, { event: "DELETE", label: "Delete", variant: "danger" }] })
CREATE -> Creating
(render-ui modal { type: "form", entity: "Task", fields: ["title", "description", "status"], submitEvent: "SAVE", cancelEvent: "CANCEL" })
EDIT -> Editing
(render-ui modal { type: "form", entity: "Task", fields: ["title", "description", "status"], submitEvent: "SAVE", cancelEvent: "CANCEL" })
DELETE -> Listing
(persist delete Task @entity.id)
(notify success "Task deleted")
}
state Creating {
SAVE -> Listing
(render-ui modal null)
(persist create Task @payload)
(fetch Task)
(render-ui main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "EDIT", label: "Edit" }, { event: "DELETE", label: "Delete", variant: "danger" }] })
(notify success "Task created")
CANCEL -> Listing
(render-ui modal null)
(fetch Task)
(render-ui main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "EDIT", label: "Edit" }, { event: "DELETE", label: "Delete", variant: "danger" }] })
}
state Editing {
SAVE -> Listing
(render-ui modal null)
(persist update Task @entity)
(fetch Task)
(render-ui main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "EDIT", label: "Edit" }, { event: "DELETE", label: "Delete", variant: "danger" }] })
(notify success "Task updated")
CANCEL -> Listing
(render-ui modal null)
(fetch Task)
(render-ui main { type: "entity-table", entity: "Task", fields: ["title", "status"], columns: ["title", "status"], itemActions: [{ event: "EDIT", label: "Edit" }, { event: "DELETE", label: "Delete", variant: "danger" }] })
}
}
page "/tasks" -> TaskCrud
}

This single file defines the full application: a Task entity with four fields, a TaskCrud trait with list/create/edit/delete flows, and a page that wires it to the /tasks route.

Here is what the app looks like when running. Try clicking "New Task" to see the form modal:

orbital TaskManager {
entity Task [runtime] {
id : string
title : string
description : string
status : string
}
trait TaskCrud -> Task [interaction] {
initial: Listing
state Listing {
INIT -> Listing
(fetch Task)
(render-ui main { type: "stack", direction: "vertical", gap: "lg", children: [{ type: "stack", direction: "horizontal", gap: "md", align: "center", children: [{ type: "typography", content: "My Task Manager", variant: "h2" }, { type: "button", label: "New Task", event: "CREATE", variant: "primary", icon: "plus" }] }, { type: "divider" }, { type: "typography", variant: "body", color: "muted", content: "No tasks yet. Click New Task to get started." }] })
CREATE -> Creating
(render-ui modal { type: "stack", direction: "vertical", gap: "md", children: [{ type: "typography", content: "New Task", variant: "h3" }, { type: "input", label: "Title", placeholder: "Enter task title" }, { type: "textarea", label: "Description", placeholder: "Describe the task" }, { type: "select", label: "Status", options: [{ value: "pending", label: "Pending" }, { value: "in_progress", label: "In Progress" }, { value: "done", label: "Done" }] }, { type: "stack", direction: "horizontal", gap: "md", children: [{ type: "button", label: "Save", event: "SAVE", variant: "primary" }, { type: "button", label: "Cancel", event: "CANCEL", variant: "secondary" }] }] })
EDIT -> Editing
DELETE -> Listing
}
state Creating {
SAVE -> Listing
(render-ui modal null)
(fetch Task)
(render-ui main { type: "stack", direction: "vertical", gap: "lg", children: [{ type: "typography", content: "My Task Manager", variant: "h2" }, { type: "divider" }, { type: "data-list", entity: "Task", fields: ["title", "status"] }] })
CANCEL -> Listing
(render-ui modal null)
(render-ui main { type: "stack", direction: "vertical", gap: "lg", children: [{ type: "typography", content: "My Task Manager", variant: "h2" }, { type: "divider" }, { type: "data-list", entity: "Task", fields: ["title", "status"] }] })
}
state Editing {
SAVE -> Listing
(render-ui modal null)
(fetch Task)
(render-ui main { type: "stack", direction: "vertical", gap: "lg", children: [{ type: "typography", content: "My Task Manager", variant: "h2" }, { type: "divider" }, { type: "data-list", entity: "Task", fields: ["title", "status"] }] })
CANCEL -> Listing
(render-ui modal null)
(render-ui main { type: "stack", direction: "vertical", gap: "lg", children: [{ type: "typography", content: "My Task Manager", variant: "h2" }, { type: "divider" }, { type: "data-list", entity: "Task", fields: ["title", "status"] }] })
}
}
page "/tasks" -> TaskCrud
}
Loading preview...

2. Validate

Check that the program is correct before compiling:

orb validate my-app.orb

You should see output confirming zero errors and zero warnings. If there are issues, the validator prints the exact location and a description of each problem.

3. Compile

Generate the full-stack TypeScript application:

orb compile my-app.orb --shell typescript

This creates a my-app/ directory containing the generated React frontend, Express backend, and shared types.

4. Install Dependencies

cd my-app
npm install

5. Run the Dev Server

npm run dev

This starts both the frontend (Vite) and backend (Express) in development mode.

6. Open in Browser

Navigate to http://localhost:5173. You will see:

  • A data table for tasks (initially empty)
  • A "New Task" button that opens a form in a modal
  • Edit and Delete actions on each row
  • Toast notifications on create, update, and delete

Try creating a few tasks, editing one, and deleting another. The full CRUD lifecycle works out of the box from the state machine you defined.

What You Just Built

From a single .orb file, the compiler generated:

  • React components for the entity table, form modal, and page layout
  • Express API routes for CRUD operations on the Task entity
  • Shared TypeScript types for the Task entity, used by both client and server
  • State machine logic that drives the UI transitions (Listing, Creating, Editing states)
  • Mock data layer so the app works immediately without a database

Every button click, form submission, and table action follows the closed-circuit pattern: Event, Guard, Transition, Effects, UI Response. The state machine in your .orb file controls the entire flow.

Next Steps