{"id":50321109,"url":"https://github.com/sadiq-bd/backend-starter","last_synced_at":"2026-05-29T03:30:50.855Z","repository":{"id":358341808,"uuid":"1216304670","full_name":"sadiq-bd/backend-starter","owner":"sadiq-bd","description":"A production-ready backend starter built on Hono + Cloudflare Workers, with Drizzle ORM ","archived":false,"fork":false,"pushed_at":"2026-05-16T21:15:14.000Z","size":18,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T23:36:24.125Z","etag":null,"topics":["bun","cloudflare-workers","drizzle-orm","feature-based-architecture","hono","production","typescritpt"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sadiq-bd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2026-04-20T19:17:36.000Z","updated_at":"2026-05-16T21:15:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sadiq-bd/backend-starter","commit_stats":null,"previous_names":["sadiq-bd/backend-starter"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sadiq-bd/backend-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadiq-bd%2Fbackend-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadiq-bd%2Fbackend-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadiq-bd%2Fbackend-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadiq-bd%2Fbackend-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sadiq-bd","download_url":"https://codeload.github.com/sadiq-bd/backend-starter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sadiq-bd%2Fbackend-starter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33635961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["bun","cloudflare-workers","drizzle-orm","feature-based-architecture","hono","production","typescritpt"],"created_at":"2026-05-29T03:30:50.241Z","updated_at":"2026-05-29T03:30:50.843Z","avatar_url":"https://github.com/sadiq-bd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"left\"\u003e \u003cimg src=\"https://api.sadiq.workers.dev/app/github/repo/backend-starter/views\" alt=\"\" /\u003e \u003c/p\u003e\n\n# Backend Starter\n\nA production-ready backend starter built on **Hono** + **Cloudflare Workers**, with **Drizzle ORM** for the database layer and **Zod** for validation.\n\n## Stack\n\n| Layer | Technology |\n|---|---|\n| Runtime | [Cloudflare Workers](https://developers.cloudflare.com/workers/) |\n| Framework | [Hono](https://hono.dev/) v4 |\n| Database | [Cloudflare D1](https://developers.cloudflare.com/d1/) (SQLite) |\n| ORM | [Drizzle ORM](https://orm.drizzle.team/) |\n| Validation | [Zod](https://zod.dev/) |\n| Testing | [Vitest](https://vitest.dev/) + [@cloudflare/vitest-pool-workers](https://developers.cloudflare.com/workers/testing/vitest-integration/) |\n\n## Project Structure\n\n```\nsrc/\n├── app.ts                        # App entry — middleware \u0026 route registration\n├── routes/\n│   └── index.ts                  # Central route registry\n├── features/\n│   └── test-feature/             # Example feature module\n│       ├── index.ts              #   Route definitions\n│       ├── config.ts             #   Feature-scoped config (DB binding)\n│       ├── controller.ts         #   Request handlers\n│       └── service.ts            #   Business logic (extends AppService)\n├── lib/\n│   ├── core/\n│   │   └── AppService.ts         # Base service class (DB access, logging)\n│   ├── database/\n│   │   ├── index.ts              # DB factory (D1 by default)\n│   │   └── d1/\n│   │       ├── index.ts          #   D1 Drizzle client\n│   │       └── schema.ts         #   Drizzle table schemas\n│   ├── middleware/\n│   │   ├── basicAuth.ts          # HTTP Basic auth (DB-backed credentials)\n│   │   ├── cacheHandler.ts       # Response caching (native CF cache + fallback)\n│   │   ├── errorHandler.ts       # Global error handler (HTTPException, Zod, AppError)\n│   │   ├── notFoundHandler.ts    # 404 handler\n│   │   └── rateLimiter.ts        # CF rate limiting\n│   └── utils/\n│       ├── base64.ts             # Base64 encode/decode\n│       ├── cache.ts              # Cache abstraction (CF Cache API + memory fallback)\n│       ├── env.ts                # Environment variable accessor\n│       ├── error.ts              # AppError class\n│       ├── formatters.ts         # Number formatting\n│       ├── json.ts               # JSON response helpers\n│       ├── remote.ts             # Client IP / connection info\n│       └── sqlite.ts             # SQLite column helpers (timestamp)\n├── types/\n│   ├── env.ts                    # Env bindings interface\n│   └── database.ts               # Database type aliases\n└── __tests__/                    # Test suites\n    ├── app.test.ts               # Integration — routes, 404, CORS\n    ├── error-handler.test.ts     # Error handler branches\n    └── utils.test.ts             # Unit — AppError, base64, formatCount, AppService\n```\n\n## Getting Started\n\n### Prerequisites\n\n- [Bun](https://bun.sh/) (or Node.js 18+)\n- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) (`bun add -g wrangler`)\n- A Cloudflare account with Workers \u0026 D1 enabled\n\n### Install\n\n```bash\nbun install\n```\n\n### Development\n\n```bash\nbun run dev\n```\n\nThis starts a local Workers dev server via `wrangler dev` with hot reload.\n\n### Deploy\n\n```bash\nbun run deploy\n```\n\nDeploys to Cloudflare Workers with minification enabled.\n\n## Database\n\nThis starter uses **Cloudflare D1** with **Drizzle ORM**.\n\n### Schema\n\nEdit `src/lib/database/d1/schema.ts` to define your tables using Drizzle's schema builder.\n\n### Generate Migrations\n\n```bash\nbun run db:generate\n```\n\n### Apply Migrations\n\n```bash\nbun run db:migrate\n```\n\n## Type Generation\n\nRegenerate Cloudflare binding types from `wrangler.jsonc`:\n\n```bash\nbun run cf-typegen\n```\n\n## Testing\n\nTests run in the Cloudflare Workers runtime via `@cloudflare/vitest-pool-workers`.\n\n```bash\n# Run all tests\nbun run test\n\n# Watch mode\nbun run test:watch\n```\n\n### Test Structure\n\n| File | Scope | What it covers |\n|---|---|---|\n| `app.test.ts` | Integration | Root route, 404 handler, CORS headers |\n| `error-handler.test.ts` | Integration | HTTPException, Zod, AppError, generic 500 |\n| `utils.test.ts` | Unit | `AppError`, `base64`, `formatCount`, `AppService` |\n\n## Architecture\n\n### Feature Modules\n\nEach feature lives in `src/features/\u003cname\u003e/` with its own:\n\n- **`index.ts`** — Hono sub-app with route definitions\n- **`config.ts`** — Feature-scoped configuration (database bindings, etc.)\n- **`controller.ts`** — Thin request handlers that delegate to services\n- **`service.ts`** — Business logic class extending `AppService`\n\nFeatures are mounted in `src/routes/index.ts`.\n\n### Middleware Pipeline\n\nThe request pipeline applies middleware in this order:\n\n1. **Context Storage** — Makes the Hono context available globally via `getContext()`\n2. **Rate Limiter** — IP-based rate limiting using Cloudflare's built-in rate limiter\n3. **CORS** — Cross-origin request handling\n4. **Route-specific** — `basicAuth()`, `tokenized()`, `cacheHandler()` can be applied per-route\n\n### AppService Base Class\n\nAll services extend `AppService\u003cDatabase\u003e` which provides:\n\n- **`this.db()`** — Type-safe database client accessor\n- **`this.log()`** — Structured logging with timestamp and class name\n\n### Error Handling\n\nThe global error handler catches and normalizes:\n\n| Error Type | Status | Response |\n|---|---|---|\n| `HTTPException` | Original status | `{ success, message }` |\n| `ZodError` | 422 | `{ success, message, errors[] }` |\n| `AppError` | Custom status | `{ success, message }` + custom headers |\n| Generic `Error` | 500 | `{ success, message: \"Internal Server Error\" }` |\n\n### JSON Response Helpers\n\nUse `jsonSuccess()` and `jsonError()` for consistent API responses:\n\n```ts\nimport { jsonSuccess, jsonError } from \"@/lib/utils/json\";\n\n// { success: true, message: \"Users fetched\", data: [...] }\nreturn jsonSuccess(\"Users fetched\", { data: users });\n\n// { success: false, message: \"Not authorized\" }\nreturn jsonError(\"Not authorized\", {}, 403);\n```\n\n## Adding a New Feature\n\n1. Create a directory under `src/features/`:\n\n```\nsrc/features/my-feature/\n├── index.ts\n├── config.ts\n├── controller.ts\n└── service.ts\n```\n\n2. Define your service:\n\n```ts\n// service.ts\nimport AppService from \"@/lib/core/AppService\";\nimport { SqliteDB } from \"@/types/database\";\n\nexport class MyFeatureService extends AppService\u003cSqliteDB\u003e {\n  async getItems() {\n    return this.db().select().from(items);\n  }\n}\n```\n\n3. Create the controller:\n\n```ts\n// controller.ts\nimport { jsonSuccess } from \"@/lib/utils/json\";\nimport { Context } from \"hono\";\nimport { myFeatureConfig } from \"./config\";\nimport { MyFeatureService } from \"./service\";\n\nexport const MyFeatureController = {\n  async list(c: Context) {\n    const service = new MyFeatureService(myFeatureConfig.db());\n    return jsonSuccess(\"Items\", { data: await service.getItems() });\n  },\n};\n```\n\n4. Register routes in `src/routes/index.ts`:\n\n```ts\nimport myFeature from \"@/features/my-feature\";\n\n// inside registerRoutes()\n.route('/my-feature', myFeature)\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsadiq-bd%2Fbackend-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsadiq-bd%2Fbackend-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsadiq-bd%2Fbackend-starter/lists"}