The backend that survives the restart

Workflows written as plain async code, made durable by the compiler. Domain code that never sees a string ID. Distributed safety enforced by the type system, not your discipline.

$npx create-justscale
poker.process.tsTypeScript

Real createProcess wrap, real imports, real types. Hover anything in the panel — Monaco resolves it against the live @justscale/* type definitions.

Six things JustScale does that other frameworks don't

The differences are mechanical, not marketing.

Durable Processes

Workflows that suspend on signals or timeouts and resume after restarts. Plain async code, transformed by the compiler into an opcode-based state machine.

ID-Free Domain

No string IDs in domain code. A persistent entity is its own reference. Storage owns IDs; your code passes typed entities and lets the compiler check the rest.

Distributed-Safe by Construction

Mutations require Locked<T>. Acquiring a lock is atomic with the read. The same domain code runs against an in-memory lock locally, and Postgres advisory locks across 20 nodes — without changing.

Transport Agnostic

Define routes once. Same controller serves HTTP, WebSocket, gRPC, CLI, and SSE. Same DI, same middleware, same guards.

If it Compiles, it Works

Missing dependency? Type error. Bare Persistent<T> passed to update? Type error. Locked<T> sent across the wire? Refused at serialization time.

No Runtime Magic

No decorators, no reflect-metadata, no proxies you can't reason about. defineService takes a plain object. The token IS the class. What you read is what runs.

From async to durable, in three steps

The compiler does the work. You write what happens.

1. Declare the signals

Path-based, typed, routable. The path IS the topic.

Loading editor...
Step 1 of 3Hover over code to see types

Distributed-safe, by construction

Every mutating repository method requires Locked<T>. The only way to get one is to ask the repository, which acquires the lock atomically with the read. The same code runs against an in-memory lock locally and a Postgres advisory lock across 20 nodes — without changing.

Files
transfer.service.tsTypeScript

If it compiles, it works. Pass a bare Persistent<Account> to accounts.update? Type error. Try to send a Locked<T>across the wire? The serializer refuses — locks don't survive process boundaries, so pretending they do would be a lie.

Wire it up

Domain, infra, app. Three layers. Domain code never imports infra. Swap Postgres for in-memory in tests without touching a service.

Files
src/domain/account.tsTypeScript

Ready to write t-shirt code?

The installer detects your package manager and IDE, scaffolds a project, and gets you to just dev in under a minute.

npx create-justscale