The easiest TypeScript Backend Framework specially built for AWS Lambda Serverless.
npm install -g crayfish-jscrayfish 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-apiGenerate a new controller.
Example:
cd my-api
crayfish generate-controller user
# Creates src/controller/user-controller.tsGenerate 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:3000Build and package for AWS Lambda deployment.
Example:
npm run build
crayfish pack
# Ready to deploy to AWS Lambdanpm run buildcrayfish 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/uiOverride 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
