Spring Boot-style framework for TypeScript with Express and TypeORM
npm install fragment-tsFragment TS is a Spring Boot-inspired TypeScript framework for Express and TypeORM, built around dependency injection and decorators, with a fully modular CLI.
This README is intentionally long and comprehensive so it can serve as a landing page for the framework site.
- Overview
- Quick Start
- Philosophy
- Project Structure
- Bootstrapping
- Dependency Injection
- HTTP Pipeline
- TypeORM
- Plugins
- Mail
- Notifications
- Jobs and Cron
- Documentation Generator
- CLI Overview
- Configuration
- Testing
- Logging
- Troubleshooting
- FAQ
- Glossary
Fragment TS is designed for teams who want consistency, explicit structure, and fast iteration in TypeScript.
The framework centers on class decorators that describe behavior and a DI container that resolves dependencies.
Key ideas:
- Everything is a class with metadata.
- No hidden magic: configuration is in fragment.json.
- One unified CLI that can be called programmatically.
- Features are optional but designed to work together.
1. Install the CLI: npm install -g fragment-ts
2. Initialize: fragment init my-app
3. Move into the directory: cd my-app
4. Run the dev server: fragment serve
Hello World example:
``ts
import {
FragmentApplication,
FragmentWebApplication,
Controller,
Get,
} from "fragment-ts";
@Controller("/")
class HelloController {
@Get()
index() {
return { message: "Hello Fragment" };
}
}
@FragmentApplication({ port: 3000 })
class App {}
async function bootstrap() {
const app = new FragmentWebApplication();
await app.bootstrap(App);
}
bootstrap();
`
Fragment TS borrows the clarity of Spring Boot and the ergonomics of modern TypeScript.
Your application should read like an architecture diagram.
Your configuration should be explicit and stable.
Your framework should be a partner, not a black box.
Structure is controlled by fragment.json:
- layered: src/controllers, src/services, src/repositoriesmodule
- : src/modules/feature
- : src/features/
The CLI generators honor the structure you choose.
`ts
import { FragmentApplication, FragmentWebApplication } from "fragment-ts";
@FragmentApplication({ port: 3000, autoScan: true })
class Application {}
async function bootstrap() {
const app = new FragmentWebApplication();
await app.bootstrap(Application);
}
bootstrap();
`
Constructor injection is automatic, property injection is opt-in.
`ts
import { Service, Autowired, Value } from "fragment-ts";
@Service()
class MailService {
@Value("${MAIL_FROM:noreply@example.com}")
private from!: string;
}
@Service()
class UserService {
constructor(private mailer: MailService) {}
@Autowired()
private secondaryMailer!: MailService;
}
`
Fragment wraps Express and adds middleware, guards, interceptors, and exception filters.
`ts
import { Controller, Get, FragmentGuard } from "fragment-ts";
class AuthGuard {
canActivate(req: any) {
return !!req.user;
}
}
@FragmentGuard(AuthGuard)
@Controller("/secure")
class SecureController {
@Get()
profile() {
return { ok: true };
}
}
`
TypeORM is wired through TypeORMModule and fragment.json.@InjectRepository
Use to access repositories.
Plugins are first-class and can be installed with fragment add .
Use qualifiers to disambiguate multiple plugin instances.
Mailers can be registered via @Mailer or via config-driven providers in fragment.json.@MailTemplate
Templates can be registered with .
Notifications resolve channels through @NotificationChannel metadata.fragment.json
Default channels are configured in .
Jobs can be defined with @Job() and scheduled with @Cron() or the fluent scheduler.
Use @ApiTag, @ApiOperation, @ApiResponse, and @ApiProperty to generate OpenAPI-style docs./docs
Runtime docs are served at and /docs.json./docs/modules/:module
Per-module runtime docs can be served at .
The CLI (fragment or frg) provides scaffolding, diagnostics, and automation.
Selected commands:
- fragment init [dir]
- fragment init --type=plugin
- fragment serve
- fragment build
- fragment test
- fragment lint
- fragment route:list
- fragment config:cache
- fragment cache:clear
- fragment env:init
- fragment env:list
- fragment env:use
- fragment env:diff [file]
- fragment doc:generate
- fragment plugin:list
- fragment plugin:info
- fragment plugin:remove
- fragment plugin:enable
- fragment plugin:disable
- fragment add
- fragment make:controller
- fragment make:service
- fragment make:resource
- fragment make:dto
- fragment make:middleware
- fragment make:guard
- fragment make:job
- fragment make:mail
- fragment make:notification
- fragment make:view
- fragment make:store
- fragment make:component
- fragment make:template
Fragment is configured via fragment.json.
Example:
`json`
{
"structure": { "type": "module" },
"verbose": false,
"logging": { "level": "info", "structured": false },
"docs": {
"path": "/docs",
"enabled": true,
"perModule": true,
"perModuleRoutes": true
},
"database": {
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "password",
"database": "fragment"
},
"mail": {
"default": "primary",
"mailers": {
"primary": { "driver": "console", "from": "noreply@example.com" }
}
},
"notifications": { "defaultChannels": ["mail"] },
"jobs": { "enabled": true, "timezone": "UTC" },
"plugins": ["my-fragment-plugin"],
"pluginAutoQualify": true
}
Configuration keys (high-level):
- structure.type
- verbose
- logging.level
- logging.structured
- database.\*
- database.entities
- database.migrations
- mail.default
- mail.mailers
- mail.templatesDir
- mail.queue.enabled
- notifications.defaultChannels
- jobs.enabled
- jobs.timezone
- docs.enabled
- docs.path
- docs.outputDir
- docs.template
- docs.perModule
- docs.perModuleRoutes
- plugins
- pluginAutoQualify
Fragment includes a lightweight test runner:
`ts
import { describe, it, expect, initTestRunner } from "fragment-ts";
initTestRunner();
describe("math", () => {
it("adds", () => {
expect(1 + 1).toBe(2);
});
});
`
Use FragmentLogger with configurable levels and structured output.verbose or logging.level controls the output verbosity.
Core decorators:
- @FragmentApplication(options)
- @Controller(path?)
- @Service()
- @FragmentRepository()
- @Injectable(scope?)
- @AutoConfiguration()
Injection decorators:
- @Autowired()
- @Inject(token)
- @InjectRepository(entity)
- @Value(expression)
- @Qualifier(name)
- @Optional()
- @Lazy()
HTTP decorators:
- @Get(path?)
- @Post(path?)
- @Put(path?)
- @Delete(path?)
- @Patch(path?)
- @Body()
- @Param(name?)
- @Query(name?)
- @Header(name?)
- @Req()
- @Res()
Pipeline decorators:
- @FragmentMiddleware(MiddlewareClass)
- @FragmentGuard(GuardClass)
- @FragmentInterceptor(InterceptorClass)
- @FragmentExceptionFilter(ExceptionFilterClass)
Lifecycle decorators:
- @PostConstruct()
- @PreDestroy()
- @OnStartup(order?)
- @OnShutdown(order?)
Plugin decorators:
- @Plugin(options)
- @Plugin(token, qualifier?) (property)
- @OnPluginInit(order?)
- @OnPluginShutdown(order?)
Mail decorators:
- @Mailer(options)
- @Mail(qualifier?) (property)
- @MailTemplate(options)
Notification decorators:
- @NotificationChannel(options)
Jobs decorators:
- @Job(options)
- @Cron(expression, options?)
Docs decorators:
- @ApiTag(tag)
- @ApiOperation({ summary, description })
- @ApiResponse({ status, description, type, isArray, example })
- @ApiProperty({ description, required, example, type })
- If decorators are not executed, ensure experimentalDecorators and emitDecoratorMetadata are true.@Api*
- If no components are discovered, check scan patterns and file suffixes.
- If MobX is missing, install it and rerun the build.
- If docs output is empty, confirm controllers are registered and metadata exists.
Q: Does Fragment require TypeORM?
A: No, but TypeORM integration is first-class.
Q: Can I run commands programmatically?
A: Yes. Use CommandRunner.run().
Q: How do I disable docs routes?
A: Set docs.enabled to false in fragment.json.
- Plugin: External extension with lifecycle hooks.
- Module: A grouped feature in module structure.
- Use @FragmentApplication(options) to register core application components.@Controller(path?)
- Use to register core application components.@Service()
- Use to register core application components.@FragmentRepository()
- Use to register core application components.@Injectable(scope?)
- Use to register core application components.@AutoConfiguration()
- Use to register core application components.@Autowired()
- clarifies injection intent and dependency scope.@Inject(token)
- clarifies injection intent and dependency scope.@InjectRepository(entity)
- clarifies injection intent and dependency scope.@Value(expression)
- clarifies injection intent and dependency scope.@Qualifier(name)
- clarifies injection intent and dependency scope.@Optional()
- clarifies injection intent and dependency scope.@Lazy()
- clarifies injection intent and dependency scope.@Get(path?)
- defines routing and request binding explicitly.@Post(path?)
- defines routing and request binding explicitly.@Put(path?)
- defines routing and request binding explicitly.@Delete(path?)
- defines routing and request binding explicitly.@Patch(path?)
- defines routing and request binding explicitly.@Body()
- defines routing and request binding explicitly.@Param(name?)
- defines routing and request binding explicitly.@Query(name?)
- defines routing and request binding explicitly.@Header(name?)
- defines routing and request binding explicitly.@Req()
- defines routing and request binding explicitly.@Res()
- defines routing and request binding explicitly.@FragmentMiddleware(MiddlewareClass)
- keeps cross-cutting concerns declarative.@FragmentGuard(GuardClass)
- keeps cross-cutting concerns declarative.@FragmentInterceptor(InterceptorClass)
- keeps cross-cutting concerns declarative.@FragmentExceptionFilter(ExceptionFilterClass)
- keeps cross-cutting concerns declarative.@PostConstruct()
- ensures deterministic lifecycle order.@PreDestroy()
- ensures deterministic lifecycle order.@OnStartup(order?)
- ensures deterministic lifecycle order.@OnShutdown(order?)
- ensures deterministic lifecycle order.@Plugin(options)
- exposes plugin lifecycle and injection points.@Plugin(token, qualifier?) (property)
- exposes plugin lifecycle and injection points.@OnPluginInit(order?)
- exposes plugin lifecycle and injection points.@OnPluginShutdown(order?)
- exposes plugin lifecycle and injection points.@Mailer(options)
- keeps mail logic modular and testable.@Mail(qualifier?) (property)
- keeps mail logic modular and testable.@MailTemplate(options)
- keeps mail logic modular and testable.@NotificationChannel(options)
- registers custom delivery channels.@Job(options)
- schedules background work consistently.@Cron(expression, options?)
- schedules background work consistently.@ApiTag(tag)
- keeps API docs close to controllers.@ApiOperation({ summary, description })
- keeps API docs close to controllers.@ApiResponse({ status, description, type, isArray, example })
- keeps API docs close to controllers.@ApiProperty({ description, required, example, type })
- keeps API docs close to controllers.fragment init [dir]
- CLI: is part of the primary workflow.fragment init --type=plugin
- CLI: is part of the primary workflow.fragment serve
- CLI: is part of the primary workflow.fragment build
- CLI: is part of the primary workflow.fragment test
- CLI: is part of the primary workflow.fragment lint
- CLI: is part of the primary workflow.fragment route:list
- CLI: is part of the primary workflow.fragment config:cache
- CLI: is part of the primary workflow.fragment cache:clear
- CLI: is part of the primary workflow.fragment env:init
- CLI: is part of the primary workflow.fragment env:list
- CLI: is part of the primary workflow.fragment env:use
- CLI: is part of the primary workflow.fragment env:diff [file]
- CLI: is part of the primary workflow.fragment doc:generate
- CLI: is part of the primary workflow.fragment plugin:list
- CLI: is part of the primary workflow.fragment plugin:info
- CLI: is part of the primary workflow.fragment plugin:remove
- CLI: is part of the primary workflow.fragment plugin:enable
- CLI: is part of the primary workflow.fragment plugin:disable
- CLI: is part of the primary workflow.fragment add
- CLI: is part of the primary workflow.fragment make:controller
- CLI: is part of the primary workflow.fragment make:service
- CLI: is part of the primary workflow.fragment make:resource
- CLI: is part of the primary workflow.fragment make:dto
- CLI: is part of the primary workflow.fragment make:middleware
- CLI: is part of the primary workflow.fragment make:guard
- CLI: is part of the primary workflow.fragment make:job
- CLI: is part of the primary workflow.fragment make:mail
- CLI: is part of the primary workflow.fragment make:notification
- CLI: is part of the primary workflow.fragment make:view
- CLI: is part of the primary workflow.fragment make:store
- CLI: is part of the primary workflow.fragment make:component
- CLI: is part of the primary workflow.fragment make:template
- CLI: is part of the primary workflow.structure.type
- Config: is a stable knob for behavior.verbose
- Config: is a stable knob for behavior.logging.level
- Config: is a stable knob for behavior.logging.structured
- Config: is a stable knob for behavior.database.*
- Config: is a stable knob for behavior.database.entities
- Config: is a stable knob for behavior.database.migrations
- Config: is a stable knob for behavior.mail.default
- Config: is a stable knob for behavior.mail.mailers
- Config: is a stable knob for behavior.mail.templatesDir
- Config: is a stable knob for behavior.mail.queue.enabled
- Config: is a stable knob for behavior.notifications.defaultChannels
- Config: is a stable knob for behavior.jobs.enabled
- Config: is a stable knob for behavior.jobs.timezone
- Config: is a stable knob for behavior.docs.enabled
- Config: is a stable knob for behavior.docs.path
- Config: is a stable knob for behavior.docs.outputDir
- Config: is a stable knob for behavior.docs.template
- Config: is a stable knob for behavior.docs.perModule
- Config: is a stable knob for behavior.docs.perModuleRoutes
- Config: is a stable knob for behavior.plugins
- Config: is a stable knob for behavior.pluginAutoQualify` is a stable knob for behavior.
- Config: