An open API service indexing awesome lists of open source software.

https://github.com/forinda/kick-js

A declarative progressive backend framework
https://github.com/forinda/kick-js

api dependency-injection expressjs joi kickjs mongoose typescript vite vitejs zod

Last synced: 29 days ago
JSON representation

A declarative progressive backend framework

Awesome Lists containing this project

README

          



KickJS


A production-grade, decorator-driven Node.js framework for TypeScript — runs on Express, Fastify, or h3, swap the engine in one line.


npm version
license
node version

NestJS ergonomics without the complexity — decorators, DI, module system, code generators, and end-to-end type safety, powered by Zod and Vite.

## Install

```bash
pnpm add @forinda/kickjs express reflect-metadata zod
pnpm add -D @forinda/kickjs-cli
```

Or scaffold a new project:

```bash
npx @forinda/kickjs-cli new my-api
cd my-api && pnpm dev
```

## Hello World

A fresh `kick new my-api` scaffolds a complete project. Here are the files that matter, exactly as the CLI generates them:

```ts
// src/modules/hello/hello.service.ts
import { Service } from '@forinda/kickjs'

@Service()
export class HelloService {
greet(name: string) {
return { message: `Hello ${name} from KickJS!`, timestamp: new Date().toISOString() }
}

healthCheck() {
return { status: 'ok', uptime: process.uptime() }
}
}
```

```ts
// src/modules/hello/hello.controller.ts
import { Controller, Get, Autowired, type Ctx } from '@forinda/kickjs'
import { HelloService } from './hello.service'

@Controller()
export class HelloController {
@Autowired() private readonly helloService!: HelloService

@Get('/')
index(ctx: Ctx) {
ctx.json(this.helloService.greet('World'))
}

@Get('/health')
health(ctx: Ctx) {
ctx.json(this.helloService.healthCheck())
}
}
```

```ts
// src/modules/hello/hello.module.ts
import { defineModule } from '@forinda/kickjs'
import { HelloController } from './hello.controller'

export const HelloModule = defineModule({
name: 'HelloModule',
build: () => ({
routes() {
return { path: '/hello', controller: HelloController }
},
}),
})
```

```ts
// src/modules/index.ts
import { defineModules } from '@forinda/kickjs'
import { HelloModule } from './hello/hello.module'

export const modules = defineModules().mount(HelloModule())
```

```ts
// src/index.ts
import 'reflect-metadata'
import './config' // registers env schema before bootstrap
import { bootstrap } from '@forinda/kickjs'
import { modules } from './modules'

export const app = await bootstrap({ modules })
```

> `KickRoutes.HelloController['index']` is generated by `kick typegen`
> (auto-runs on `kick dev`), giving fully typed `ctx.params`, `ctx.body`,
> and `ctx.query`. Env keys typed via `KickEnv` after running typegen too.

## Highlights

**Factory-first extensibility** — the full extension surface. No class hierarchies to inherit from.

```ts
defineAdapter() defineModule()
definePlugin() defineHttpContextDecorator()
```

**Custom DI container** — constructor and property injection, three scopes (singleton / transient / request), zero external dependency. Slash-delimited tokens carry intent and scope from the type definition straight through to error messages.

```ts
const REPO = createToken('app/users/repository')
container.register(REPO, PrismaUserRepo)
```

**Typed Context Contributors** — `defineHttpContextDecorator()` populates `ctx.set('key', value)` once per request. `dependsOn` is typed against `keyof ContextMeta` so typos are TS errors, not boot-time `MissingContributorError`. Same registration runs across HTTP / WS / queue / cron.

**End-to-end type safety via typegen** — `kick typegen` (auto on `kick dev`) emits augmentations from source scan. `ctx.params/body/query`, `@Inject` literals, and asset paths all narrow as you save.

```ts
KickRoutes // ctx.params / body / query per route
KickJsPluginRegistry // @Inject literals
KickAssets // typed asset paths
KickEnv // ConfigService.get keys
```

**Decorator-driven**:

```ts
@Controller @Get @Post @Put @Delete @Patch
@Service @Autowired @Middleware
@Cacheable @Cron @Asset
```

**DDD generators** — full hook surface emitted so you delete what you don't need.

```bash
kick g module users # complete module scaffold
kick g adapter # full hook surface
kick g plugin # full plugin shape
```

**`kick g agents`** — regenerates `CLAUDE.md` at the project root and `.agents/AGENTS.md` / `.agents/GEMINI.md` / `.agents/COPILOT.md` + per-skill `.agents/skills//SKILL.md`. One CLI command keeps every AI coding agent in sync with the latest framework conventions.

**Cooperative shutdown** — observability SDKs (OpenTelemetry, Sentry) own SIGTERM without racing the framework. `Promise.allSettled` for adapter shutdown so one slow flush can't block siblings.

```ts
bootstrap({ processHooks: 'errors-only' })
```

**Zod-native validation** — schemas double as OpenAPI documentation.

**Vite HMR** — single-port dev server, zero-downtime hot reload, preserves DB/Redis/Socket connections, customizable HMR log.

**Auto OpenAPI** — Swagger UI and ReDoc from decorators + Zod schemas; pluggable schema parser + UI renderer for adopters who want corporate branding.

**Built-in middleware** — helmet, CORS, CSRF, rate limiting, file uploads, request logging, request scope (AsyncLocalStorage).

**DevTools dashboard** — `/_debug` browser panel with topology, container, routes, metrics; adapter authors expose state via `introspect()` ([type lives in `@forinda/kickjs` directly](https://forinda.github.io/kick-js/guide/devtools.html) — no extra import needed) + `devtoolsTabs()` from `@forinda/kickjs-devtools-kit`.

**Extensible CLI** — custom commands in `kick.config.ts`, plugin generators registered as real Commander subcommands so they appear in `kick g --help`, jiti-powered TS config loading, walk-up project-root resolution.

## Ecosystem

KickJS deliberately ships a small, stable core. The extension surface — `defineAdapter()`, `definePlugin()`, `defineHttpContextDecorator()`, plus `getRequestValue` and `processHooks` from `@forinda/kickjs` — is the same one the framework itself uses, so adopter-built integrations stay first-class: typed DI, lifecycle hooks, the contributor pipeline, and DevTools `introspect()` all work without any framework changes.

### Core packages

Three packages ship with every project — `kick new` always installs them, and `kick add` won't list them as optional. Together they're the framework runtime + the dev/build/scaffold loop:

| Package | Description |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@forinda/kickjs`](packages/kickjs/) | Core framework — DI, decorators, pluggable HTTP runtimes (Express / Fastify / h3), routing, middleware, contributors, request store, `processHooks` |
| [`@forinda/kickjs-vite`](packages/vite/) | Vite plugin — single-port HMR, typegen watcher, customizable HMR log |
| [`@forinda/kickjs-cli`](packages/cli/) | Scaffolding, DDD generators, custom commands, `kick g agents`, jiti-powered TS config loading, walk-up project root |

### Optional packages

Everything else — swagger, the db family, queue, ws, devtools, drizzle, prisma — installs on demand. The catalog moves over time, so the live list lives next to the CLI rather than this README:

```bash
kick add --list # current optional catalog
kick add swagger drizzle # install several at once
```

Browse `packages/` in this repo for the full source layout.

## Example Apps

Runnable reference apps live in **[forinda/kickjs-examples-archive](https://github.com/forinda/kickjs-examples-archive)** — Drizzle / Prisma / Mongoose / `@forinda/kickjs-db` task apps, multi-tenant patterns, and a minimal starter. Open the archive's README for the current catalog.

```bash
git clone https://github.com/forinda/kickjs-examples-archive
```

The fastest way to start a real project is still `kick new ` — `kick.config.ts`, `tsconfig`, `vite.config`, modules, and env wiring scaffolded for you. The archive is for reading reference patterns; the CLI is for starting your own.

## CLI

```bash
# Project lifecycle
kick new my-api # Scaffold project (rest | ddd | cqrs | minimal)
kick dev # Vite HMR dev server (~200ms reload)
kick build && kick start # Production build + run

# Code generation
kick g module users # Full DDD module
kick g module users --repo prisma # …with a Prisma repository
kick g module users --repo drizzle # …with a Drizzle repository
kick g scaffold post title:string body:text:optional # CRUD from field defs
kick g controller users # Single @Controller class
kick g service payment # Single @Service class
kick g adapter websocket # AppAdapter — every hook stubbed + JSDoc
kick g plugin analytics # KickPlugin — every hook stubbed + JSDoc
kick g job / dto / guard / middleware / test # one-file scaffolds

# AI agent docs (regenerate from upstream templates after framework upgrades)
kick g agents # CLAUDE.md (root) + .agents/{AGENTS,GEMINI,COPILOT}.md + .agents/skills/*/SKILL.md
kick g agents --only skills -f # Just the per-skill SKILL.md files
kick g agents --only gemini -f # Just .agents/GEMINI.md

# Package management
kick add swagger drizzle # Install KickJS packages with peer deps
kick add --list # Show all available packages

# Introspection
kick info # System + framework version
kick inspect # Inspect a running KickJS app
kick tinker # Interactive REPL with full DI graph
```

## Technical Decisions

| Area | Choice | Why |
| ---------- | ---------------------- | -------------------------------------------------------------------- |
| Runtime | Node.js 20+ | LTS with native ESM |
| HTTP | Express / Fastify / h3 | Pluggable runtime — pick the engine at bootstrap |
| Validation | Zod | Runtime + static types, doubles as OpenAPI schema |
| Build | Vite 8 | Unified toolchain — library builds, HMR, SSR |
| Test | Vitest 4 | ESM-native, fast, Vite-compatible |
| Logging | console (pluggable) | Zero-dep default; swap for Pino / Winston via `Logger.setProvider()` |
| Monorepo | pnpm + Turborepo | Efficient deps, build caching |

## Runtime Compatibility

| Feature | Node 20+ | Node 22+ | Node 24+ | Bun | Deno |
| --------------- | -------- | -------- | -------- | ------------ | ---- |
| Production | Yes | Yes | Yes | Experimental | No |
| Dev Mode (HMR) | Yes | Yes | Yes | No | No |
| Tests (Vitest) | Yes | Yes | Yes | Partial | No |
| CLI (`kick`) | Yes | Yes | Yes | Experimental | No |
| Pure ESM Import | Yes | Yes | Yes | Yes | Yes |

> **Node 20** is the minimum supported version (LTS with native ESM).
>
> **Bun**: core DI and decorators work; full HTTP pipeline is experimental.
>
> **Deno**: blocked by `reflect-metadata`. The default logger is `console`-based (zero deps), so logging is not a blocker.

## Documentation

**[forinda.github.io/kick-js](https://forinda.github.io/kick-js/)**

New here? The **[Samples guide](https://forinda.github.io/kick-js/guide/samples)** is a one-page, copy-pasteable tour of the recommended patterns — controllers, DI, modules, config, context decorators, error handling, adapters, and extending the CLI — each linking into the full guide. It doubles as the mental model.

## Contributing

```bash
git clone https://github.com/forinda/kick-js.git
cd kick-js
pnpm install && pnpm build && pnpm test
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.

## License

MIT — see [LICENSE](LICENSE)