Skip to content

Getting Started

Orbital Express is an opinionated Express.js + Sequelize (PostgreSQL) framework for building really good backend APIs fast. It combines Django's feature-based folder structure with Rails' Model-View-Controller concept, and layers in a background-job system (Bull/Redis) and real-time Socket.IO alongside the web server.

This guide gets you from zero to a running local environment. If you have not read What is Orbital Express? yet, do that first — it explains the mental model before you touch any code.


What You Should Know First

Orbital Express is not a beginner framework. Before you use it, you should be comfortable with everything below. If any of these feel unfamiliar, work through the linked resources first — the investment will pay off immediately.

JavaScript Fundamentals

If you're new to JavaScript, start here:

Advanced JavaScript (required)

You need to deeply understand how JavaScript actually works — not just the syntax, but the runtime, scope, closures, prototypes, and the event loop. These two courses are the best available:

  • JavaScript: Understanding the Weird Parts by Anthony Alicea — free intro on YouTube; full course on Udemy. Watch this first.
  • ES6 and Modern JavaScript — Stephen Grider's ES6 JavaScript: The Complete Developer's Guide (Udemy). Covers arrow functions, destructuring, classes, modules, async/await, and everything added since ES5.

Node.js (required)

  • Learn and Understand NodeJS by Anthony Alicea (Udemy) — covers the Node runtime, the event loop, streams, modules, and how Express fits in. Go through Section 9 and stop there — you don't need beyond that to use this framework effectively.

Express.js (required)

Orbital Express is built on top of Express. You don't need to be an expert, but you should understand routing, middleware, the request/response cycle, and how next() works.

Databases — PostgreSQL

JavaScript Libraries Used in This Framework

You don't need to master these before starting, but you will encounter all of them. The Level column tells you where to focus first:

LibraryWhat it's forLevelDocs
SequelizePostgreSQL ORM — models, migrations, queries🟢 Must Knowsequelize.org
JoiSchema validation for every incoming request🟢 Must Knowjoi.dev
JestTest runner — integration tests, assertions🟢 Must Knowjestjs.io · Cheatsheet
Moment.jsDate/time handling and timezone support🟢 Must Knowmomentjs.com
Passport.jsAuth middleware — used under the hood for JWT strategy🟢 Must Knowpassportjs.org
RedisIn-memory store — powers queues, sessions, caching🟡 Good to Knowredis.io/docs
Socket.IOReal-time bidirectional events over WebSockets🟡 Good to Knowsocket.io/docs
BullBackground job queues — built on top of Redis🟡 Good to Knowgithub.com/OptimalBits/bull
accounting.jsMoney formatting for display🔵 Optionalaccounting.js
currency.jsMoney math and calculations🔵 Optionalcurrency.js.org

Legend:

  • 🟢 Must Know — you will use this on every single feature you build
  • 🟡 Good to Know — you will encounter it; understanding it prevents confusion
  • 🔵 Optional — only relevant for certain project types (e.g. financial apps)

Where to start

Get Sequelize, Joi, and Jest solid first. Redis and Socket.IO you'll understand naturally once you start building features that use queues and real-time events.


System Prerequisites

Before you install anything, make sure your machine has:

RequirementVersionNotes
Node.jsv22.x.xUse nvm to pin the version per project
PostgreSQL14+Must be running before yarn migrate or yarn test
Redis7+See Redis setup below — installed on your machine via Homebrew
Yarn1.x (classic)npm install -g yarn

Knowledge assumed

Orbital Express is not a "hello world" starter. This guide assumes you understand JavaScript (ES6+), Node.js, and the basic request/response lifecycle of an Express app. If any of those feel shaky, read up on them before continuing.


Installation

There are two ways to start a new project. Option A is recommended.

The fastest way to start. The CLI scaffolds a complete, configured project in seconds — picks your database name, auth providers, email provider, and optional integrations, then wires them all up for you.

bash
npx create-orbital-app my-api

That's it. Answer the prompts, then:

bash
cd my-api
cp config/.env.template config/.env.development
# fill in your environment variables
createdb my_api_dev
createdb my_api_test
yarn migrate
yarn s

Source

create-orbital-app is a separate open-source package — view the source at github.com/Hackbyrd/create-orbital-app.


Option B — Clone the repo manually

If you want to start from the raw framework repo and configure everything yourself:

bash
git clone https://github.com/Hackbyrd/orbital-express.git my-api
cd my-api
yarn install

All dependencies are pinned to exact versions — no ^ or ~ ranges anywhere in package.json. Keep it that way.

Always pin exact versions

When you add any new dependency, always pass --exact:

bash
yarn add <module> --exact          # regular dependency
yarn add <module> --exact --dev    # dev dependency

Range versions (^1.2.3, ~1.2.3) let the package manager silently install a different version on a fresh checkout or CI run. Exact pins guarantee every developer, every CI run, and every deploy installs the identical dependency tree.


Redis — Local Machine Setup

Redis is installed directly on your local machine — there is no project-local redis/ folder anymore (older versions of Orbital-Express built a copy of Redis inside the repo; that approach is deprecated).

Mac (Homebrew):

bash
brew install redis

Windows: Redis has no official native Windows build — install it through WSL2 (sudo apt-get install redis-server).

Linux (Debian/Ubuntu): sudo apt-get install redis-server.

Then manage the Redis service with the yarn commands (they wrap brew services):

bash
yarn redis           # start redis as a background service (alias: yarn redis:start)
yarn redis:restart   # restart the service
yarn redis:stop      # stop the service
yarn redis:status    # list brew services and their status
yarn redis:logs      # view service logs
yarn redis:info      # show info about the service

Full details are in docs/redis.txt. Redis must be running for the worker process, Socket.IO, and the test suite.

Local dev only

The locally installed Redis is purely for running the app on your machine. In production, connect to a managed Redis (Heroku Redis, Redis Cloud, etc.) via the REDIS_URL config var.


Configuration

All environment variables live in per-environment files under config/. The committed template is config/.env.template — it is the canonical reference for every variable the app accepts.

Create your local env files

bash
cp config/.env.template config/.env.development
cp config/.env.template config/.env.test

Fill in the values for each file. The .env.development and .env.test files are gitignored — they never appear in the repository.

Use a separate database for tests

DATABASE_URL in .env.test must point to a different Postgres database than development. The test suite drops and recreates tables on every run.

Required variables

The source of truth is always config/.env.template, but these are the minimum needed to boot:

VariableWhat it is
NODE_ENVdevelopment / test / production — selects which .env.* loads
DATABASE_URLPostgres connection string
REDIS_URLRedis connection (Bull queues + Socket.IO adapter)
ACCESS_TOKEN_SECRETSigning secret for the short-lived access JWT
REFRESH_TOKEN_SECRETSigning secret for refresh tokens — must differ from the access secret
ACCESS_TOKEN_EXPIRES_INAccess-token lifetime, e.g. 15m
REFRESH_TOKEN_EXPIRES_INRefresh-token lifetime, e.g. 60d

All auth vars in every env file

ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET, ACCESS_TOKEN_EXPIRES_IN, and REFRESH_TOKEN_EXPIRES_IN must be present in every env file, including .env.test. If they are missing from .env.test, auth tests fail in confusing ways. Keep the two secrets distinct, and never commit real secrets — only .env.template is committed.

Every time you add a new config variable to the app, update .env.template so the next developer who pulls your changes knows it exists.

How the config loads

config/config.js is what the Sequelize CLI reads to run migrations — it is pointed at by .sequelizerc at the repo root. It loads the matching .env.<env> by NODE_ENV and exports one block per environment.

database/index.js is the Sequelize connection used by the running app server — it reads the same DATABASE_URL. Two separate entry points, same database.


Running Locally

Orbital-Express has three processes. You need all three running during development:

bash
yarn s      # web server (index.js → server.js, clustered via throng)
yarn w      # background worker (worker.js — processes Bull queue jobs)
yarn cron   # cron daemon (cronjobs.js — enqueues scheduled work)

Why three processes?

ProcessWhat it does
Web server (yarn s)Handles all incoming HTTP and WebSocket requests.
Worker (yarn w)Runs background jobs — tasks that are too slow or heavy for the request/response cycle (report generation, third-party API calls, bulk operations).
Cron (yarn cron)A clock process — triggers scheduled work (e.g. "send a daily email at noon"). Typically enqueues a worker task rather than doing the work itself.

The cron process should run as exactly one instance in production. The web server and worker can scale horizontally.

Development shortcut

In local development you can open three terminal tabs, one per process. In production these are separate dynos/containers.

For the full command reference, database backup/restore, Heroku deploy steps, health probes, and ngrok webhook testing, see the Operations & Deploy reference.


Your First Migration

Once Postgres is running and your config/.env.development is configured:

bash
yarn migrate

This applies all pending migrations in migrations/ to your development database, in order. The Sequelize CLI reads config/config.js, which picks up DATABASE_URL from .env.development.

bash
yarn migrate:prod    # run against production DATABASE_URL
yarn rollback        # roll back the last migration (development)

Never edit schema.sql to change the database

database/schema.sql is documentation — it is never executed. The real schema changes live in migrations/. Always create a migration file via:

bash
sequelize migration:create --name descriptive-name

Then record the same change in database/schema.sql so every developer can read the full schema in one place.


Running Tests

bash
yarn test

The test command runs three things in sequence: yarn lang (compiles and validates i18n), applies test fixtures, then runs the full Jest suite with --runInBand.

Postgres and Redis must be running

The integration tests hit a real Postgres database (pointed at by DATABASE_URL in .env.test) and a real Redis. Start both before running yarn test.

Test files mirror source file locations exactly:

  • Feature action tests → app/<Feature>/tests/integration/
  • Feature task tests → app/<Feature>/tests/tasks/
  • Global helper tests → test/helpers/<name>.test.js
  • Global service tests → test/services/<name>.test.js

Project Layout at a Glance

Almost everything you build day-to-day lives in app/ — one folder per feature (one per database table). Everything else at the repo root is shared infrastructure.

repo root
├── app/                  # ALL features — one folder per feature (table)
├── index.js              # web entry point (clustered via throng)
├── server.js             # Express app: middleware, routes, socket, error handler
├── worker.js             # background worker — registers all queue task processors
├── cronjobs.js           # cron clock — schedules jobs
├── routes.js             # global route aggregator (mounts every feature's routes.js)
├── models.js             # global model aggregator (scans app/*/model.js)
├── middleware/           # global Express middleware (id, args, auth, error, exit)
├── services/             # third-party wrappers + shared infra (queue, redis, socket, email…)
├── helpers/              # small pure utility functions shared across features
├── database/             # schema.sql, sequence.js, seed/, backups/, index.js
├── migrations/           # ordered schema changes applied by yarn migrate
├── languages/            # global i18n source strings (compiled by yarn lang)
├── locales/              # compiled i18n output — never edit by hand
├── config/               # per-environment .env files + config glue
├── docs/                 # all deep documentation
└── test/                 # global test entry: fixtures, helper/service unit tests

The app/ folder is where you spend most of your time. Each feature folder holds everything related to that feature:

app/
└── Order/
    ├── model.js
    ├── routes.js
    ├── controller.js
    ├── actions/
    │   ├── index.js
    │   ├── V1Create.js
    │   └── V1Get.js
    ├── tasks/
    ├── tests/
    ├── languages/
    └── mailers/

Scaffolding Your First Feature

The generator is the only way to create new feature files. Never create them by hand.

bash
yarn gen Order                    # scaffold the Order feature folder
yarn gen Order -a V1Create        # add an action to an existing feature
yarn gen Order -t V1ProcessTask   # add a background task
yarn gen Order -m OrderMailer     # add a mailer

After scaffolding, immediately remove the generator's default placeholder files:

bash
yarn del Order -a V1Example       # removes the placeholder action + its export entry

Use yarn del, not rm

yarn del removes the file and cleans up its entry in actions/index.js (or tasks/index.js). Using rm directly leaves a broken export pointing at a deleted file.

After generating, run yarn lang to compile i18n, then yarn test to confirm the scaffold passes the suite.


Next Steps