Introduction
What is JustScale and why should you use it?
JustScale is a modern TypeScript framework for building scalable backend applications with compile-time type safety. Unlike traditional frameworks that rely on runtime reflection or decorators, JustScale leverages TypeScript's type system to validate dependencies, routes, and middleware at compile time.
The Core Concept
Controllers are application entry points.
Whether triggered by an HTTP request, a CLI command, or an internal event - each invocation is a fresh entry into your application with:
- Full dependency injection (scoped per request)
- Middleware chain execution
- Guard validation
- Observability (logging, tracing)
The transport is just the trigger source. Your business logic stays the same whether it's handling an HTTP POST, a CLI command, or a background job. This is what we mean by transport-agnostic.
import { createController } from '@justscale/core';
import { Get, Post } from '@justscale/http';
import { Cli } from '@justscale/cli';
import { body } from '@justscale/http/builder';
import { UserService } from './user-service';
import { CreateUserSchema } from './schemas';
const UsersController = createController('/users', {
inject: { users: UserService },
routes: (services) => ({
// HTTP: GET /users
list: Get('/').handle(({ res }) => {
res.json(services.users.findAll());
}),
// HTTP: POST /users
create: Post('/')
.apply(body(CreateUserSchema))
.handle(({ body, res }) => {
res.json(services.users.create(body));
}),
// CLI: users list
listCli: Cli('list').handle(({ io }) => {
io.table(services.users.findAll());
}),
}),
});Same controller. Same services. Same type safety. Different entry points.
What JustScale Provides
- Dependency Injection - Type-safe service management with compile-time validation. Missing dependencies are caught before your code runs.
- Controllers - Transport-agnostic entry points with automatic type inference and route composition.
- Middleware & Guards - Composable request processing with type-safe context accumulation.
- Features - Modular, reusable application components that encapsulate services, controllers, and configuration.
- Transports - HTTP, CLI, and more. Each transport is a separate package that plugs into the same core.
Key Features
Compile-Time Type Safety
All dependencies are resolved and validated at compile time. If you forget a service or have a circular dependency, TypeScript tells you before you run your code:
import { createClusterBuilder } from '@justscale/core';
import { UserService } from './user-service';
import { UsersController } from './users-controller';
const app = createClusterBuilder()
.add(UserService) // Missing Database dependency!
.add(UsersController)
.build();
// TypeScript Error: __dependencies_missing__: DatabaseMiddleware with Context Accumulation
Middleware in JustScale accumulates type-safe context. Each .use() call adds properties to the handler context:
import { createController } from '@justscale/core';
import { Post } from '@justscale/http';
import { UserService } from './user-service';
import { authenticate } from './middleware/authenticate';
import { parseBody } from './middleware/parse-body';
import { isOwner } from './guards/is-owner';
const UsersController = createController('/users', {
inject: { users: UserService },
routes: (services) => ({
update: Post('/:id')
.use(authenticate) // Adds { user: User }
.use(parseBody) // Adds { body: UpdateUserDto }
.guard(isOwner) // Can access user and params
.handle(({ user, body, params }) => {
services.users.update(params.id, body);
// All properties are typed
}),
}),
});Zero Runtime Magic
No decorators, no reflection, no metadata. JustScale uses plain TypeScript types and functions. What you write is what runs:
import { createService } from '@justscale/core';
import { Database } from './database';
export const UserService = createService({
inject: { db: Database },
factory: ({ db }) => ({
findAll: () => db.query('SELECT * FROM users'),
create: (data) => db.insert('users', data),
}),
});Feature-Based Architecture
Build reusable features that encapsulate everything needed for a capability. Features compose together and dependencies resolve automatically:
import { createClusterBuilder, wrapWithCluster } from '@justscale/cluster';
import { LoggingFeature } from './features/logging';
import { UsersController } from './controllers/users';
import { UserService } from './services/user';
const built = createClusterBuilder()
.add(LoggingFeature)
.add(UserService)
.add(UsersController)
.build();
const cluster = wrapWithCluster(built.compile());
await cluster.serve({ http: 3000 });Who is JustScale For?
JustScale is ideal for:
- TypeScript developers who want maximum type safety without sacrificing developer experience
- Teams building maintainable, modular applications that need to scale
- Projects that need transport flexibility - expose your logic via HTTP today, add CLI tomorrow, events next week
- Developers who prefer explicit code over magical frameworks