S
Core Concepts

How StarkForge Works

The big picture of configuration, collections, feature modules and the path a request takes through the framework

StarkForge turns a description of your backend into a running Express app. This page follows that conversion from the first line of your code to the moment a response leaves the server, so you know what each part of the framework does before you read the detailed pages.

The Big Picture

  1. 1
    1. You describe your backend with options and a list of collections.
    2. new Forge checks the options and builds the services that everything shares.
    3. Each collection has a type, and the feature module for that type turns its routes into Express routes.
    4. build() assembles the middleware and mounts every collection under /api/v1.
    5. start() connects to the database and starts listening.

This is the smallest program that goes through all five steps:

TypeScript
// src/server.ts
import { Forge, collection, fields } from "@starklabs/forge";

const products = collection({
  type: "crud",
  route: "products",
  model: "Product",
  schema: {
    name: fields.requiredString,
    price: fields.requiredNumber,
  },
  routes: [
    { method: "get", path: "/", handler: "readAll", auth: "public" },
    { method: "get", path: "/:id", handler: "read", auth: "public" },
  ],
});

const forge = new Forge({ collections: [products] });
await forge.start();

The collection is step 1 and new Forge is step 2. The key type: "crud" selects the CRUD module in step 3, which turns the two route entries into GET /api/v1/products and GET /api/v1/products/:id. The call to start() performs steps 4 and 5.

Collections and Feature Modules

A collection describes one resource or feature. Its type decides which feature module handles it. The module knows the handlers of that type, checks that every route of the collection is valid and registers the routes on an Express router.

TypeWhat its module provides
crudDatabase resources: read, list, create, update, delete and file handlers
authSign-up, sign-in, sessions, one-time codes, magic links, social sign-in and two-factor codes
accountThe signed-in user's own profile and role
healthA health check

You write the crud collections yourself. The other types come built in: when you set builtinConfig.auth or builtinConfig.account, StarkForge generates the auth or account collection for you, and it adds a health collection automatically unless you define your own. Generated collections are ordinary collections. They pass through the same pipeline as yours, with the same limits and the same error format, and forge.collections lists all of them, generated ones first.

The Request Pipeline

Every request travels through the same stages, in this order:

  1. 1
    1. A request id is attached. It is returned in the X-Request-Id header and repeated as requestId in every error.
    2. Secure headers are set.
    3. CORS decides whether a browser on another origin may call the API.
    4. The request is logged, when logRequests is on.
    5. The response is compressed.
    6. The global rate limit counts the request.
    7. JSON and form bodies are parsed, up to bodyLimit, and cookies are read.
    8. The input sanitizer removes keys that start with $, keys that contain a dot and the key __proto__.
    9. The origin guard refuses state-changing browser requests from sites that are not in your front-end URLs.
    10. The router picks the route. Credential routes pass the stricter rate limit, then the authenticator checks the access level and the roles, and routes with files parse the upload.
    11. The handler validates the body, does its work and writes the response.

A request that matches no route ends in the not-found handler. An error thrown at any stage ends in the central error handler. Both answer with the same JSON error shape, which the Errors page describes.

StageWhat it protects against
Secure headersCommon browser-side attacks, through the headers that helmet sets
CORS and origin guardRequests from websites you did not allow
Rate limitsFloods and password guessing
Body limitOversized requests
Input sanitizerNoSQL operator injection and prototype pollution
AuthenticatorCallers without the right access level or role
ValidationMissing, malformed or unexpected body fields
Error handlerInternal details leaking into error responses

Services and Dependencies

new Forge builds the objects that the modules share once: the validated configuration, the logger, the data source, token signing, password hashing, encryption, email, uploads, the authenticator and more. They are collected in forge.services and handed to each feature module explicitly. There are no global singletons, so several Forge instances can run in one process, which the test helpers rely on.

The second constructor argument replaces any of these services with your own. Its keys are logger, dataSource, emailProvider, storageProviders and fetch, which social sign-in uses to call the provider. Most apps never need it. Tests use it to swap MongoDB, email delivery and file storage for in-memory fakes.

Build, Start and Stop

MethodWhat it does
build()Assembles the middleware, mounts every collection and returns the Express app. It does not connect to the database or listen, and calling it twice is safe. Use it when you wrap the app yourself
start()Calls build(), connects to the database, listens on port, prints the banner when logRequests is on and returns the http.Server. A second call returns the same server
stop()Stops accepting connections, waits for requests in progress and closes the database connection
use(module)Registers a custom feature module, or replaces a built-in one. It must run before build() or start(), or it throws a ConfigurationError

forge.app is the Express app itself. On SIGINT (Ctrl + C) and on SIGTERM, which hosts send when they stop a container, start() has installed handlers that call stop() and then exit the process, so a deployment ends without cutting off requests. stop() removes those handlers again, and they are not installed in the test environment.

Where to Go Next

Routes

Declare endpoints, access levels and per-route settings.

Authentication

Add sign-up, sign-in and sessions.

:::