{"id":47605318,"url":"https://github.com/dorsale/dorsale","last_synced_at":"2026-04-01T19:11:09.179Z","repository":{"id":210312286,"uuid":"642315785","full_name":"dorsale/dorsale","owner":"dorsale","description":"Dorsale is a Bun-based backend framework","archived":false,"fork":false,"pushed_at":"2026-02-08T16:50:34.000Z","size":414,"stargazers_count":2,"open_issues_count":6,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-08T22:34:29.530Z","etag":null,"topics":["backend","bun","decorators","dependency-injection","framework","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/dorsale","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dorsale.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-05-18T09:46:29.000Z","updated_at":"2025-07-11T17:20:03.000Z","dependencies_parsed_at":"2023-12-15T02:56:00.901Z","dependency_job_id":"9e6e7d9f-1f36-4237-99b5-2c71ac168df7","html_url":"https://github.com/dorsale/dorsale","commit_stats":null,"previous_names":["dj-256/dorsale","dorsale/dorsale"],"tags_count":125,"template":false,"template_full_name":null,"purl":"pkg:github/dorsale/dorsale","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dorsale%2Fdorsale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dorsale%2Fdorsale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dorsale%2Fdorsale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dorsale%2Fdorsale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dorsale","download_url":"https://codeload.github.com/dorsale/dorsale/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dorsale%2Fdorsale/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","bun","decorators","dependency-injection","framework","typescript"],"created_at":"2026-04-01T19:11:08.499Z","updated_at":"2026-04-01T19:11:09.166Z","avatar_url":"https://github.com/dorsale.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dorsale\n\nDorsale is a Bun-based backend TypeScript framework. It is built on top of the Bun server and [wint](https://github.com/aquapi/wint) for routing.\nDorsale uses decorators to define elements of your application.  \nIt is a work in progress, and is not ready for\nproduction use.\nIf you benchmark it, please let me know the results!\n\n## Installation\n\nQuick and easy, just:\n```shell\nbun add dorsale\n```\n\nYou also need to enable TypeScript's decorators feature by adding the following options to your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n```\n\n## Getting started\n\n### Your first dorsale app\n\nThe setup is intentionally minimalistic. Bootstrapping a Dorsale application is as simple as:\n\n```ts\nimport { dorsale } from 'dorsale';\n\ndorsale({ port: 8080 });\n```\n\nThis will start a server on port 8080. You can then add controllers, services, and repositories to your application.\n\n### Full application example\nA full example could look like this:\n\n```\nsrc\n├── index.ts\n├── user.ts\n├── userFinder.ts\n├── userManager.ts\n├── userController.ts\n```\n\n```ts\n// index.ts\nimport { dorsale } from 'dorsale';\n\ndorsale({ port: 8080 });\n```\n\n```ts\n// user.ts\nexport interface User {\n  id: string;\n  email: string;\n  password: string;\n}\n```\n\n```ts\n// userFinder.ts\nimport { User } from \"./user\";\n\nexport interface UserFinder {\n  findAllUsers(): Promise\u003cUser[]\u003e;\n\n  findUserById(id: string): Promise\u003cUser | undefined\u003e;\n\n  findUserByEmail(email: string): Promise\u003cUser | undefined\u003e;\n}\n```\n\n```ts\n// userManager.ts\nimport { UserEditor } from \"./userEditor\";\nimport { UserFinder } from \"./userFinder\";\nimport { User } from \"./user\";\nimport { Component } from \"dorsale\";\n\n@Component\nexport class UserManager implements UserFinder {\n  users: User[] // = [... some users];\n\n  findAllUsers(): Promise\u003cUser[]\u003e {\n    return Promise.resolve(this.users);\n  }\n\n  findUserByEmail(email: string): Promise\u003cUser | undefined\u003e {\n    const user = this.users.find((u) =\u003e u.email === email);\n    return Promise.resolve(user);\n  }\n\n  findUserById(id: string): Promise\u003cUser | undefined\u003e {\n    const user = this.users.find((u) =\u003e u.id === id);\n    return Promise.resolve(user);\n  }\n}\n```\n\n```ts\n// userController.ts\nimport { Controller, Get } from \"dorsale\";\nimport type { UserFinder } from \"./userFinder\";\n\n@Controller()\nexport class UserController {\n  constructor(private readonly userFinder: UserFinder) {\n  }\n\n  @Get(\"/\")\n  getAll() {\n    return this.userFinder.findAllUsers();\n  }\n\n  @Get(\"/:id\")\n  getById(id: string) {\n    return this.userFinder.findUserById(id);\n  }\n}\n```\n\nYou just have to run the file containing the call to the `dorsale` function, and you're good to go!\nThe other components will be automatically discovered and injected. This reduces the amount of boilerplate code you have\nto write.\n\n⚠️ Important: you **must** import interfaces as `type` in the controller file, this is a limitation of Bun. (\nsee https://github.com/oven-sh/bun/issues/8618)\n\nBy default, Dorsale will look for components in the current directory, but you can change this by passing a `rootDir`\noption\nto the `dorsale` call.\n\n```ts\ndorsale({ port: 8080, rootDir: \"myFolder/relative/to/the/current/file\" });\n```\n\n## Controllers\n\n### Controller classes\n\nControllers are classes that define the routes exposed by your application. They are decorated with `@Controller()`.\n```ts\nimport { Controller } from \"dorsale\";\n\n@Controller()\nexport class UserController {\n    // ... your routes\n}\n```\n\nYou can also specify a prefix for all the routes defined in a controller by passing it as an argument to the decorator.\n```ts\n@Controller(\"/users\")\nexport class UserController {\n    // ... your routes\n}\n```\n\n### Routes\n\nRoutes are defined by decorating methods with `@Get`, `@Post`, `@Put`, `@Patch`, or `@Delete`.\n```ts\nimport { Controller, Get } from \"dorsale\";\n\n@Controller()\nexport class UserController {\n    @Get(\"/hello\")\n    getHello() {\n        return \"Hello world!\";\n    }\n}\n```\nIn the example above, a GET route will be exposed at `/hello`, and will return the string `\"Hello world!\"`.\n\n### Route parameters\n\nYou can define route parameters by adding a colon (`:`) before the parameter name in the route path.\n```ts\nimport { Controller, Get } from \"dorsale\";\n\n@Controller()\nexport class UserController {\n    @Get(\"/users/:id\")\n    getUserById(id: string) {\n        // ...\n    }\n}\n```\n\n### Query parameters\n\nQuery parameters are defined by adding a `@Query` decorator to the parameter.\n```ts\nimport { Controller, Get, Query } from \"dorsale\";\n\n@Controller()\nexport class UserController {\n    @Get(\"/users\") // e.g. GET /users?page=1\u0026limit=10\n    getUsers(@Query page: number, @Query limit: number) {\n        // ...\n    }\n}\n```\nIf some query parameters are not provided in the request, they will be `undefined`.\n\n### Body\n\nYou can access the body of the request by adding a `@Body` decorator to a parameter.\n```ts\nimport { Controller, Post, Body } from \"dorsale\";\n\n@Controller()\nexport class UserController {\n    @Post(\"/users\")\n    createUser(@Body user: User) {\n        // ...\n    }\n}\n```\n\n## Testing\n\nComing soon!\n\n## Contributing\n\nContributions are welcome! Feel free to open an issue or a PR if you have any suggestions or bug reports.\nPlease follow the GitHub flow when contributing (see [here](https://guides.github.com/introduction/flow/) for more\ninformation).\nThanks for your interest in Dorsale!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdorsale%2Fdorsale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdorsale%2Fdorsale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdorsale%2Fdorsale/lists"}