syntrojs
v0.8.0
Published
π₯ DUAL RUNTIME: FastAPI for Node.js AND Bun - Same Code, Maximum Performance | β‘ 3.8x Faster with Bun
Maintainers
Readme
π Status: Production Ready (Pre-1.0)
β SyntroJS is production-ready with a battle-tested core and comprehensive feature set. The framework is stable and ready for production use.
- β Battle-tested Core - 980+ tests across Node.js and Bun (100% passing)
- β CORS Fully Functional - REST and Lambda modes with comprehensive validation
- β AWS Lambda Support - Production-ready Lambda mode with full API Gateway integration
- β Router System - Group routes with prefixes and router-level middleware
- β Type-Safe Client - Testing and frontend integration with autocomplete
- β Active development - Regular updates and bug fixes
- π― v0.8.0 planned - Security & Real-time Features
Latest Release: v0.8.0 - Security Features (CSRF, JWT Refresh) + Real-time (SSE) - CHANGELOG
π― What is SyntroJS?
SyntroJS is the world's first dual-runtime framework that brings the simplicity and developer experience of FastAPI to the TypeScript ecosystem. Write your code once and run it on either Node.js for stability or Bun for maximum performance.
Key Highlights:
- π Dual Runtime: Same code runs on Node.js and Bun
- βοΈ AWS Lambda: Same code works in REST (dev) and Lambda (prod) modes
- π₯ FastAPI DX: Automatic validation, type safety, elegant error handling
- π¨ Auto Docs: Interactive Swagger UI + ReDoc out of the box
- π§ͺ Testing: SmartMutator for mutation testing in seconds
π Quick Start
Installation
npm install syntrojs zodBasic REST API
import { SyntroJS } from 'syntrojs';
import { z } from 'zod';
const app = new SyntroJS({ title: 'My API' });
// Simple GET endpoint
app.get('/hello', {
handler: () => ({ message: 'Hello World!' })
});
// POST with automatic validation
app.post('/users', {
body: z.object({
name: z.string().min(1),
email: z.string().email(),
}),
handler: ({ body }) => ({ id: 1, ...body }),
});
await app.listen(3000);That's it! π Visit http://localhost:3000/docs for interactive documentation.
AWS Lambda Mode
Same code, Lambda deployment - Just change one flag:
import { SyntroJS } from 'syntrojs';
import { z } from 'zod';
// Lambda mode: rest: false
const app = new SyntroJS({ rest: false, title: 'My API' });
app.post('/users', {
body: z.object({
name: z.string().min(1),
email: z.string().email(),
}),
handler: ({ body }) => ({ id: 1, ...body }),
});
// Export handler for AWS Lambda
export const handler = app.handler();That's it! π Deploy to AWS Lambda. Same validation, same type safety, same code.
See Lambda Usage Guide for complete examples.
β¨ Key Features
π Dual Runtime Support
Write once, run on both Node.js and Bun. Zero code changes required.
βοΈ AWS Lambda Support
Same code works in REST mode (development) and Lambda mode (production). Just set rest: false. Full API Gateway integration with automatic event detection and CORS support.
Lambda Adapters Status:
- β API Gateway: Implemented
- β SQS: Implemented
- β S3: Implemented
- β EventBridge: Implemented
π₯ FastAPI-like Developer Experience
Automatic validation with Zod, full TypeScript type safety, elegant error handling (HTTPException).
π¨ Automatic Interactive Docs
Beautiful landing page + Swagger UI + ReDoc out of the box at /docs.
π§ͺ Testing Superpower
SmartMutator for mutation testing in seconds. Type-safe client for testing and frontend integration.
π Rich Ecosystem
Middleware system, WebSockets, dependency injection, background tasks, structured logging.
π Security First
JWT, OAuth2, API Keys, and security plugins built-in.
ποΈ Extensible Architecture
Lambda adapters follow SOLID principles and can be extracted to separate packages. Test adapters independently without full framework.
π Examples
We have comprehensive examples in the examples/ directory:
Getting Started
- Quick Start - Basic API example with tests
- Dual Runtime - Same code on Node.js and Bun
Features
- HTTP Methods - Redirects, content negotiation, HEAD/OPTIONS
- Middleware - Global and path-specific middleware
- WebSockets - Real-time communication
- Documentation Config - Customizing OpenAPI docs
Advanced
- Lambda Example - Complete AWS Lambda deployment
- Bun Runtime - Bun-specific optimizations
- Demo Brutal - Performance benchmarks
See All Examples
Check the examples README for a complete list.
π₯ Dual-Runtime: Node.js vs Bun
Same code, different runtimes:
# Node.js (stability + full ecosystem)
node app.js
# Bun (maximum performance)
bun app.js| Runtime | Performance | Tests Passing | Use Case | |---------|-------------|---------------|----------| | Node.js | 89.5% of Fastify (5,819 req/s) | 728/728 (100%) | Production, plugins | | Bun | 3.8x faster (~22,000 req/s) | 458/487 (94%) | Maximum speed |
Bun Limitations
| Feature | Node.js | Bun | Status |
|---------|---------|-----|--------|
| Core API | β
Full | β
Full | Identical |
| Plugins (CORS, Helmet, etc.) | β
Full | β
Full | Production ready |
| Static files | β
Full | β Not available | v0.9.0 planned |
| getRawFastify() | β
Works | β Use getRawServer() | - |
π‘ Core Concepts
Request Validation
Automatic validation with Zod schemas:
app.post('/users', {
body: z.object({
name: z.string().min(1),
email: z.string().email(),
}),
params: z.object({
id: z.string().uuid(),
}),
query: z.object({
page: z.coerce.number().min(1).default(1),
}),
handler: ({ body, params, query }) => {
// All validated and type-safe!
return { ...body, id: params.id, page: query.page };
},
});Dependency Injection
Share services across routes:
import { inject } from 'syntrojs';
const dbService = inject(() => new Database(), { scope: 'singleton' });
app.get('/users', {
dependencies: { db: dbService },
handler: ({ dependencies }) => dependencies.db.getUsers()
});Error Handling
FastAPI-style exceptions:
import { NotFoundException, BadRequestException } from 'syntrojs';
app.get('/users/:id', {
handler: ({ params }) => {
const user = findUser(params.id);
if (!user) {
throw new NotFoundException('User not found');
}
return user;
},
});Middleware
Global or path-specific:
// Global middleware
app.use(async (ctx, next) => {
console.log(`${ctx.method} ${ctx.path}`);
await next();
});
// Path-specific
app.use('/api/*', async (ctx, next) => {
if (!ctx.headers.authorization) {
throw new UnauthorizedException('Token required');
}
await next();
});Background Tasks
Non-blocking async tasks:
app.post('/users', {
handler: ({ body, background }) => {
// Queue email send (non-blocking)
background.addTask(async () => {
await sendWelcomeEmail(body.email);
});
return { success: true };
}
});π API Reference
Creating an Application
new SyntroJS(config?: SyntroJSConfig)Configuration Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| title | string | - | API title for OpenAPI docs |
| version | string | - | API version |
| description | string | - | API description |
| runtime | 'auto' \| 'node' \| 'bun' | 'auto' | Force specific runtime |
| rest | boolean | true | REST mode (HTTP server) or Lambda mode |
| docs | boolean \| object | true | Configure documentation endpoints |
| logger | boolean | false | Enable Fastify logger |
| syntroLogger | boolean \| object | false | Enable @syntrojs/logger |
Route Registration
app.get(path: string, config: RouteConfig)
app.post(path: string, config: RouteConfig)
app.put(path: string, config: RouteConfig)
app.delete(path: string, config: RouteConfig)
app.patch(path: string, config: RouteConfig)Route Config:
interface RouteConfig {
handler: (ctx: RequestContext) => any;
body?: ZodSchema; // Request body validation
params?: ZodSchema; // Path parameters validation
query?: ZodSchema; // Query parameters validation
response?: ZodSchema; // Response validation
status?: number; // Default status code
dependencies?: object; // Dependency injection
}Server Management
REST Mode:
// Start server
const address = await app.listen(port: number, host?: string);
// Stop server
await app.close();Lambda Mode:
// Export handler
export const handler = app.handler();Request Context
interface RequestContext {
method: HttpMethod; // HTTP method
path: string; // Request path
params: any; // Path parameters (validated)
query: any; // Query parameters (validated)
body: any; // Request body (validated)
headers: Record<string, string>; // Request headers
cookies: Record<string, string>; // Cookies
correlationId: string; // Request tracking ID
timestamp: Date; // Request timestamp
dependencies: Record<string, any>; // Injected dependencies
background: {
addTask(task: () => void): void; // Queue background task
};
download(data, options): FileDownloadResponse; // File download helper
redirect(url, statusCode?): RedirectResponse; // Redirect helper
accepts: AcceptsHelper; // Content negotiation helper
}π Security
OAuth2 Password Bearer
import { OAuth2PasswordBearer } from 'syntrojs';
const oauth2 = new OAuth2PasswordBearer({ tokenUrl: '/token' });
app.get('/protected', {
dependencies: { user: oauth2 },
handler: ({ dependencies }) => ({ user: dependencies.user }),
});HTTP Bearer
import { HTTPBearer } from 'syntrojs';
const bearer = new HTTPBearer();
app.get('/api/data', {
dependencies: { token: bearer },
handler: ({ dependencies }) => ({ data: 'protected' }),
});API Key
import { APIKeyHeader, APIKeyQuery } from 'syntrojs';
// Via header
const apiKeyHeader = new APIKeyHeader({ name: 'X-API-Key' });
// Via query parameter
const apiKeyQuery = new APIKeyQuery({ name: 'api_key' });
app.get('/api/data', {
dependencies: { apiKey: apiKeyHeader },
handler: ({ dependencies }) => ({ data: 'protected' }),
});HTTP Basic Auth
import { HTTPBasic } from 'syntrojs';
const basicAuth = new HTTPBasic();
app.get('/admin', {
dependencies: { credentials: basicAuth },
handler: ({ dependencies }) => {
const { username, password } = dependencies.credentials;
return { admin: true };
},
});π§ͺ Testing
Standard Testing
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
import { app } from './app';
describe('API Tests', () => {
let server: string;
beforeAll(async () => {
server = await app.listen(0); // Random port
});
afterAll(async () => {
await app.close();
});
test('POST /users creates a user', async () => {
const port = new URL(server).port;
const res = await fetch(`http://localhost:${port}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', email: '[email protected]' })
});
const data = await res.json();
expect(res.status).toBe(200);
expect(data.name).toBe('John');
});
});Type-Safe Client
Test your API without starting a server, or use it in your frontend:
import { createClient } from 'syntrojs';
import type { App } from './app';
// Local mode (testing) - executes handlers directly
const client = createClient(app, { mode: 'local' });
// Call routes with autocomplete
const response = await client.users.get();
const user = await client.users[':id'].get({ params: { id: '123' } });
const created = await client.users.post({
body: { name: 'John', email: '[email protected]' }
});
// Remote mode (frontend) - makes HTTP requests
const apiClient = createClient(app, {
mode: 'remote',
baseUrl: 'https://api.example.com'
});See Type-Safe Client Documentation for complete examples.
SmartMutator - Mutation Testing
pnpm test:mutate| Method | Mutants | Tests | Time | |--------|---------|-------|------| | Stryker (vanilla) | 1,247 | 187,050 | 43 min | | SmartMutator | 142 | 284 | 12 sec |
Mutation Score: 58.72% (742 killed, 144 survived)
π Quality Metrics
- Tests: 1,019+ passing (Node.js 100%, Bun 94%)
- Coverage: 71.55% (Branch: 80.73%)
- Mutation Score: 58.72%
- Code Quality: 100% SOLID + DDD + Functional Programming
- Top Performers: RouteRegistry (100%), ZodAdapter (100%), DependencyInjector (95.83%)
π Production & Security
const app = new SyntroJS({
title: 'Production API',
docs: false // β
REQUIRED for production
});Security Checklist
- [ ] Disable all documentation (
docs: false) - [ ] Set proper CORS origins (not
*) - [ ] Enable rate limiting
- [ ] Configure structured logging without sensitive data
- [ ] Use environment variables for secrets
π TOON Format (v0.5.0+)
Reduce API bandwidth costs 40-60% while keeping responses human-readable.
| Feature | JSON | TOON π― | gRPC/Protobuf | |---------|------|------------|---------------| | Payload Size | 100% | 40-50% β‘ | 35-45% | | Human-Readable | β Yes | β Yes | β Binary | | Debug with curl | β Easy | β Easy | β Requires tools | | Setup Time | 5 minutes | 5 minutes | 2+ hours | | Tooling Needed | None | None | protoc, plugins |
TOON gives you the best of both worlds: gRPC's efficiency with JSON's simplicity.
See TOON Format Documentation for details.
πΊοΈ Roadmap
β v0.4.0 - REST Completion (100% COMPLETE π)
- [x] File downloads, streaming, uploads
- [x] HTTP redirects, content negotiation
β v0.5.0 - TOON Format (100% COMPLETE π)
- [x] TOON Format Support (40-60% payload reduction)
- [x] Serialization Architecture Refactor
β v0.6.0 - AWS Lambda Support (100% COMPLETE π)
- [x] Lambda Mode (
rest: false) - [x] API Gateway Integration
- [x] Dynamic Routes with pattern matching
- [x] 82 Lambda tests passing
β v0.7.0 - Router + Advanced Middleware (100% COMPLETE π)
- [x]
SyntroRouter- Group endpoints with prefixes - [x] Router-level middleware (
router.use()) - [x]
app.include(router)- Include routers in app - [x] Type-Safe Client (
createClient) - Testing & frontend integration - [x] Serializer Chain of Responsibility with
next() - [x] Serializer Priority System
- [x] Serializer Helper Methods (
registerBefore,registerAfter,registerFirst) - [x]
SyntroRouter- Group endpoints with prefixes - [x] Router-level middleware (
router.use()) - [x]
app.include(router)- Include routers in app - [x] Type-Safe Client (
createClient) - Testing & frontend integration - [x] Serializer Chain of Responsibility with
next() - [x] Serializer Priority System
- [x] Serializer Helper Methods (
registerBefore,registerAfter,registerFirst)
π¨ v0.8.0 - Security & Real-time Features
- [x] CSRF protection
- [x] JWT Refresh Tokens
- [x] Server-Sent Events (SSE)
- [ ] WebSocket rooms/namespaces
- [ ] Session management
π¨ v0.9.0 - Completeness (Optional Features)
- [ ] Static file serving (optional)
- [ ] Template rendering integrations (optional)
- [ ] Native Bun plugins
ποΈ v1.0.0 - Production Ready
- [ ] Official CLI (
create-syntrojs) - [ ] Graceful shutdown
- [ ] Complete documentation (Docusaurus)
- [ ] Migration guides
- [ ] Security audit
π Documentation
- Router System - Group routes with prefixes and middleware
- Type-Safe Client - Testing and frontend integration guide
- Lambda Usage Guide - Complete Lambda documentation
- Lambda Architecture - Adapter architecture guide
- Architecture - Framework architecture
- Examples - Code examples and demos
- CHANGELOG - Version history
π€ Contributing
We welcome contributions! Check out our GitHub repository.
π License
Apache 2.0 - See LICENSE for details.
