English | 简体中文
The TypeScript framework that builds once and runs anywhere, designed for humans and coding agents alike.
Quick Start · Deploy Anywhere · Coding Agents · AI · Examples · CLI Reference
Cell is a serverless-first, component-based, platform-independent application framework for TypeScript. You write plain classes with dependency injection; Cell turns them into a full-stack application, bundles the backend into a single file, and ships the same code to a Node.js server, a container, a single executable, Cloudflare Workers, AWS Lambda, Alibaba Cloud Function Compute, Tencent Cloud SCF or Vercel.
Cell 4 rebuilds the toolchain on Vite 8 and treats coding agents as first-class users: every command speaks JSON, every error carries a code and a fix, and every project ships with an AGENTS.md and an MCP server.
| One codebase, every runtime | Pick a preset at build time: node, cli, cloudflare, fc, scf, lambda, vercel. No platform SDK in your code, no rewrite when you move. |
| Single-file output | The backend is one dependency-inlined index.mjs. Add --single to embed the frontend as well, or --compile for a standalone executable (Bun, Deno or Node.js SEA). |
| Agent-first toolchain | --json on every command, structured CellError codes with hints, cell check for types and DI wiring, version-matched docs, and MCP tools for both the project and the running dev server. |
| Enterprise-grade architecture | Dependency injection and AOP (@Component, @Autowired, @Value, @Aspect), MVC, RPC, declarative transactions, security, JWT and OAuth2. |
| Full stack in one process | Backend MVC plus React, served on one port in development with frontend HMR and backend hot reload. |
| AI native | Provider-neutral chat models, prompts and streaming; agents and pi coding agent sessions whose tools are your own services. |
| Zero configuration | Sensible defaults everywhere. Override only what you need in cell.yml, cell.config.ts or CELL_BACKEND__* environment variables. |
| Minimal footprint | The toolchain depends on little more than Vite; cloud deployers sign their own requests instead of pulling in vendor SDKs. |
Requires Node.js ^20.19.0 || >=22.12.0.
npx @celljs/cli init backend my-app # or: fullstack (React + backend over RPC)
cd my-app
npm install
npx cell dev # http://127.0.0.1:3000, hot reload on save
A complete backend is a configuration file and a class:
# cell.yml
backend:
cell:
greeting: Hello from my-app
// src/node/home-controller.ts
import { Value } from '@celljs/core';
import { Controller, Get, Text } from '@celljs/mvc/lib/node';
@Controller()
export class HomeController {
@Value('cell.greeting')
protected readonly greeting: string;
@Get()
@Text()
home(): string {
return this.greeting;
}
}
Test it in-process, without opening a port:
import { createTestApp } from '@celljs/cli';
const app = await createTestApp({ root: process.cwd() });
const res = await app.fetch('/'); // 200 "Hello from my-app"
await app.close();
The everyday commands:
| Command | What it does |
|---|---|
cell dev |
One port for frontend and backend; HMR for the UI, hot reload for the server, automatic restart on config changes |
cell build |
Production build into .cell/output (--single, --compile, --preset <name>) |
cell preview |
Run the build output exactly as the target platform would |
cell deploy |
Build and publish with the preset's deployer; --dry-run prints the plan |
cell check |
Configuration, TypeScript types, decorator settings and DI bindings in one pass |
cell info |
Everything Cell resolved: preset, modes, components, DI modules, hooks, output state |
cell config get <key> --why |
The merged value of a setting and every file or variable that set it |
Your code stays the same; the preset decides the shape of the output and how it is deployed.
| Preset | Output | Deploy |
|---|---|---|
node (default) |
Node.js HTTP server, one index.mjs |
Anywhere Node.js runs: VM, container, PaaS |
cli |
Command-line program on Cell DI | Distribute as a file or an executable |
cloudflare |
Worker + static assets + wrangler.json |
cell deploy --preset cloudflare |
fc |
Alibaba Cloud Function Compute (custom runtime) | cell deploy --preset fc |
scf |
Tencent Cloud SCF web function | cell deploy --preset scf |
lambda |
AWS Lambda (Function URL / API Gateway) | cell deploy --preset lambda |
vercel |
Vercel Build Output API (.vercel/output) |
cell deploy --preset vercel |
cell build --single # the whole full-stack app in one file: node index.mjs
cell build --compile # a standalone executable, no Node.js required on the host
cell deploy --preset cloudflare --dry-run
Cell assumes the next developer on your project may be an AI agent, and makes the framework something an agent can use correctly on the first try (design principles).
--json on every command returns exactly one JSON result; errors are CellErrors with a stable code, a location and a hint.cell init writes AGENTS.md, a Cell skill and .mcp.json; cell agent sync keeps them matched to the installed versions; cell docs <query> searches the docs shipped with your exact dependencies.cell mcp exposes info, check, config_get, docs_search, build and deploy_plan; cell dev serves /_cell/mcp with routes, DI bindings, resolved config, recent requests, logs and errors of the running app.cell check catches type errors, missing decorator settings and broken DI bindings before anything runs; createTestApp() gives in-process integration tests.// .mcp.json (Claude Code, Cursor, CodeBuddy, ...)
{ "mcpServers": { "cell": { "command": "npx", "args": ["cell", "mcp"] } } }
import { Component, Autowired } from '@celljs/core';
import { ChatModel, ProxyChatModel, PromptTemplate } from '@celljs/ai-core';
@Component()
export class Assistant {
@Autowired(ProxyChatModel)
protected chatModel: ChatModel;
@Autowired(PromptTemplate)
protected promptTemplate: PromptTemplate;
async ask(question: string): Promise<string> {
const prompt = await this.promptTemplate.create('Answer briefly: {question}', {
variables: { question },
// pi:<provider>/<model id>, routed by ProxyChatModel to @celljs/ai-pi
chatOptions: { model: 'pi:anthropic/claude-sonnet-4-5' }
});
const response = await this.chatModel.call(prompt);
return response.result.output.content;
}
}
@celljs/ai-pi connects 20+ providers (Anthropic, OpenAI, Google, DeepSeek, Ollama and other OpenAI-compatible endpoints) behind the @celljs/ai-core ChatModel API (pi:<provider>/<model>).@celljs/ai-agent builds tool-using agents whose tools are ordinary Cell components; events stream over SSE.@celljs/ai-coding-agent hosts pi coding agent sessions inside your application, managed by DI.@celljs/tui turns an agent into an interactive command-line chat (see examples/tui-app).import { Component, Autowired, Value } from '@celljs/core';
@Component()
export class A {}
@Component()
export class B {
@Autowired()
protected a: A; // class injection
}
@Component()
export class C {
@Value('foo') // configuration injection: 'obj.xxx', 'arr[1]', ...
protected foo: string;
}
import { Controller, Get, Param, Delete, Put, Post, Body } from '@celljs/mvc/lib/node';
import { Transactional, OrmContext } from '@celljs/typeorm/lib/node';
import { User } from './entity';
@Controller('users')
export class UserController {
@Get()
@Transactional({ readOnly: true })
list(): Promise<User[]> {
return OrmContext.getRepository(User).find();
}
@Get(':id')
@Transactional({ readOnly: true })
get(@Param('id') id: number): Promise<User | null> {
return OrmContext.getRepository(User).findOneBy({ id });
}
@Post()
@Transactional()
create(@Body() user: User): Promise<User> {
return OrmContext.getRepository(User).save(user);
}
@Put()
@Transactional()
async modify(@Body() user: User): Promise<void> {
await OrmContext.getRepository(User).update(user.id, user);
}
@Delete(':id')
@Transactional()
async remove(@Param('id') id: number): Promise<void> {
await OrmContext.getRepository(User).delete(id);
}
}
// Shared contract
export const UserService = 'UserService';
export interface UserService {
hello(name: string): Promise<string>;
}
// Provider
import { Rpc } from '@celljs/rpc';
@Rpc(UserService)
export class UserServiceImpl implements UserService {
async hello(name: string): Promise<string> {
return `Hello, ${name}`;
}
}
// Consumer: a typed remote proxy is injected
import { Component } from '@celljs/core';
import { Autorpc } from '@celljs/rpc';
@Component()
export class Greeter {
@Autorpc(UserService)
protected userService: UserService;
}
Runnable applications live in examples/: backend-app, sample-app (React), security-app, jwt-app, schedule, prisma-app, docker-app, standalone-app, mycli, tui-app and coding-agent-app.
All packages are published under the @celljs scope as dual CommonJS / ES module builds.
| Area | Packages |
|---|---|
Core (packages/) |
core, logger, web, mvc, http, express-adapter, serve-static, rpc, typeorm, cache, retry, schedule, security, jwt, oauth2-core, oauth2-client, oauth2-jose |
Cloud (cloud-packages/) |
cloud, faas-adapter, lambda-adapter, fc-adapter, scf-adapter, vercel-adapter, oss, cos |
AI (ai-packages/) |
ai-core, ai-pi, ai-agent, ai-coding-agent |
UI (ui-packages/) |
react, widget, tui |
Toolchain (dev-packages/) |
cli, vite, kit |
cell CLI reference: commands, presets, deployers, cell.config.tsv3.9.0)Issues and pull requests are welcome. The repository is a Bun workspace monorepo built with Turborepo and TypeScript 7.
Prerequisites: Bun (version pinned in package.json → packageManager) and Node.js ^20.19.0 || >=22.12.0.
bun install # install dependencies and sync tsconfig references
bun run build # build all packages
bun run test # run all tests
bunx turbo run test --filter=@celljs/core # test one package
bun run lint # Biome (bun run format to fix)
bun changeset # describe your change for the next release