The easiest TypeScript Backend Framework specially built for AWS Lambda Serverless.
npm version TypeScript Node.js License
npm install -g crayfish-js
crayfish init my-api
cd my-apicrayfish start-server staging
π Your API is running at http://localhost:3000
Test it:
curl http://localhost:3000/health
# {"status": "OK"}β
Instant Scaffolding - Full serverless project in one command
β
TypeScript-First - Full type safety with decorators
β
Zero Config Routing - Auto-discovery via @Route decorator
β
AWS Ready - Cognito auth, Lambda handler pre-configured
β
MVC Pattern - Controllers, services, models with DI
β
Local Dev Server - Express.js for rapid development
β
Production Ready - Pack and deploy to AWS Lambda
When you run crayfish init my-api, you get:
my-api/
βββ src/
β βββ controller/
β β βββ auth-controller.ts # Example auth endpoints
β β βββ health-controller.ts # Health check endpoint
β βββ service/
β β βββ health-service.ts # Example service
β βββ model/
β β βββ user-model.ts # Example user model
β βββ environments/
β β βββ production.ts # Production config
β β βββ staging.ts # Staging config
β βββ types/
β β βββ project-types.ts # Custom types
β βββ index.ts # Main entry point
β βββ environment.ts # Environment loader
βββ package.json
βββ tsconfig.json
βββ .gitignore
Auto-installed dependencies:
crayfish-js- The frameworkexpress- Dev servertypescript,ts-node- TypeScript runtime@types/express,@types/node- Type definitions
Controllers handle HTTP requests using the @Route decorator.
Example:
import { BaseController, Route } from "crayfish-js"; export default class UserController extends BaseController { @Route({ method: "get", path: "/users" }) async getUsers(event: any) { return this.success({ users: [] }); } @Route({ method: "post", path: "/users", authenticated: true }) async createUser(event: any) { const body = JSON.parse(event.body); return this.success({ user: body }); } }
Services contain business logic and can be injected into controllers.
Example:
import { BaseService } from "crayfish-js"; export default class UserService extends BaseService { async findAll() { // Fetch from database return [{ id: 1, name: "John" }]; } }
Inject into controller:
import { BaseController, Route, Inject } from "crayfish-js"; import UserService from "../service/user-service"; export default class UserController extends BaseController { @Inject(UserService) private userService!: UserService; @Route({ method: "get", path: "/users" }) async getUsers() { const users = await this.userService.findAll(); return this.success({ users }); } }
Models define your data structures.
Example:
import { BaseModel } from "crayfish-js"; export default class User extends BaseModel { id: string; email: string; name: string; constructor(data: any) { super(); Object.assign(this, data); } }
CrayfishJS supports JWT and AWS Cognito authentication.
import { JwtAuthentication } from "crayfish-js"; const jwt = new JwtAuthentication({ secret: process.env.JWT_SECRET || "my-secret", expiresIn: "7d" }); @Route({ method: "post", path: "/login" }) async login(event: any) { const { email, password } = JSON.parse(event.body); // Verify credentials... const token = jwt.sign({ userId: "123", email }); return this.success({ token }); } @Route({ method: "get", path: "/me", authenticated: true }) async getMe(event: any) { const user = jwt.verify(event.headers.Authorization); return this.success({ user }); }
import { CognitoAuthentication } from "crayfish-js"; const cognito = new CognitoAuthentication({ region: "us-east-1", userPoolId: process.env.COGNITO_USER_POOL_ID!, clientId: process.env.COGNITO_CLIENT_ID! }); @Route({ method: "post", path: "/signup" }) async signup(event: any) { const { email, password } = JSON.parse(event.body); const result = await cognito.signUp(email, password); return this.success(result); }
Scaffold a new serverless project.
Example:
crayfish init my-api
Generate a new controller.
Example:
cd my-api crayfish generate-controller user # Creates src/controller/user-controller.ts
Generate a new service.
Example:
crayfish generate-service user
# Creates src/service/user-service.tsStart local Express dev server (NOT for production).
Example:
crayfish start-server staging # Loads src/environments/staging.ts # Server: http://localhost:3000
Build and package for AWS Lambda deployment.
Example:
npm run build
crayfish pack
# Ready to deploy to AWS Lambdanpm run build
crayfish pack
- Create a new Lambda function in AWS Console
- Upload the packaged code
- Set handler:
index.handler - Add API Gateway trigger
Or use AWS SAM / Serverless Framework:
sam deploy
# or
serverless deployDeclares an HTTP route.
Config:
{ method: "get" | "post" | "put" | "delete" | "patch", path: string, authenticated?: boolean // Require auth (default: false) }
Dependency injection for services.
Example:
@Inject(UserService) private userService!: UserService;
Enforces authentication on a route.
Example:
@Authenticated @Route({ method: "delete", path: "/users/:id" }) async deleteUser(event: any) { // Only authenticated users can access }
All controllers extend this class.
Methods:
success(data, statusCode = 200)- Return success responseerror(message, statusCode = 500)- Return error responseunauthorized(message)- Return 401notFound(message)- Return 404
All services extend this class.
Base class for models (optional).
Pre-configured user model with common fields (id, email, password, createdAt).
File: src/environments/production.ts
export const environment = { production: true, apiUrl: "https://api.example.com", jwtSecret: process.env.JWT_SECRET, };
Load environment:
import { environment } from "./environments/production"; console.log(environment.apiUrl);
Currently: No testing framework included.
Recommendation: Add Vitest or Jest manually.
npm install -D vitest @vitest/ui
Override BaseController methods:
export default class MyController extends BaseController { success(data: any) { return { statusCode: 200, body: JSON.stringify({ success: true, data }), }; } }
Add custom middleware logic in src/index.ts:
export const handler = async (event: any) => { // Custom middleware logic console.log("Request:", event); // Call router return router.handle(event); };
β
Never hardcode secrets - Use environment variables
β
Hash passwords - Use bcrypt (included)
β
Validate inputs - Add Zod or Joi validation
β
Use HTTPS - Always in production
β
Enable CORS - Configure API Gateway properly
- Controllers: PascalCase, suffix with
Controller - Services: PascalCase, suffix with
Service - Models: PascalCase (e.g.,
User,Product) - Files: kebab-case (e.g.,
user-controller.ts) - Routes: lowercase with hyphens (
/users,/auth/login)
Contributions welcome! Please:
- Fork the repo
- Create a feature branch:
git checkout -b feature/my-feature - Commit changes:
git commit -m 'feat: add my feature' - Push:
git push origin feature/my-feature - Open a Pull Request
GPL-3.0-only
See LICENSE file for details.
- GitHub: https://github.com/ivncmp/crayfish-js
- npm: https://www.npmjs.com/package/crayfish-js
- Author: IvΓ‘n Campillo (ivncmp@gmail.com)
Built with β€οΈ by IvΓ‘n Campillo
Inspired by modern backend frameworks like NestJS, but optimized for serverless environments.
For detailed technical documentation, see CLAUDE.md
Last updated: 22/03/2026
Version: 1.3.0