Bootstrap Project
Initializes a minimal TypeScript backend project with Hono.js, including code quality tooling (ESLint, Prettier) and a "Hello World" app.
Quick Reference
Use when: Creating a new backend service from scratch Result: A minimal project ready for adding layers via other skills
Prerequisites
- •Node.js 20+ installed
- •pnpm installed (
npm install -g pnpm) - •Git installed
Instructions
Phase 1: Project Initialization
Step 1: Create Project Directory
mkdir my-backend-service cd my-backend-service git init
Step 2: Initialize Package
pnpm init
Step 3: Install Dependencies
# Core dependencies pnpm add hono @hono/node-server zod dotenv # TypeScript and build tools pnpm add -D typescript tsx tsup @types/node # Testing pnpm add -D vitest @vitest/coverage-v8 # Linting and formatting pnpm add -D eslint typescript-eslint @eslint/js globals jiti pnpm add -D prettier eslint-config-prettier eslint-plugin-prettier
Phase 2: Configuration Files
Step 4: Create TypeScript Config
Create tsconfig.json:
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
"types": ["node"],
"rootDir": ".",
"outDir": "./dist",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*", "scripts/**/*", "tests/**/*"],
"exclude": ["node_modules", "dist", "coverage"]
}
Create tsconfig.build.json:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "coverage", "tests", "scripts"]
}
Step 5: Create Build Config
Create tsup.config.ts:
import { defineConfig } from "tsup";
export default defineConfig({
target: "node20",
entry: ["src/server.ts"],
outDir: "dist",
format: ["esm"],
sourcemap: true,
clean: true,
dts: true,
splitting: true,
treeshake: true,
esbuildOptions(options) {
options.alias = {
"@": "./src",
};
},
});
Step 6: Create Vitest Config
Create vitest.config.ts:
import path from "path";
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["tests/**/*.test.ts"],
coverage: {
provider: "v8",
reporter: ["text", "json", "html"],
all: true,
include: ["src/**/*.ts"],
exclude: [
"**/*.test.ts",
"**/coverage/**",
"**/node_modules/**",
"**/dist/**",
"**/scripts/**",
"**/src/server.ts",
],
},
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
Step 7: Create ESLint Config
Create eslint.config.ts:
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
import eslintPluginPrettier from "eslint-plugin-prettier";
export default tseslint.config(
{ ignores: ["dist", "tests"] },
{
extends: [
js.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier,
],
files: ["**/*.ts"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
prettier: eslintPluginPrettier,
},
rules: {},
},
);
Step 8: Create Prettier Config
Create prettier.config.json:
{
"semi": true,
"trailingComma": "all",
"singleQuote": false,
"printWidth": 80,
"tabWidth": 2,
"endOfLine": "auto"
}
Create .prettierignore:
**/.git **/.svn **/.hg **/node_modules pnpm-lock.yaml dist
Step 9: Update package.json
Add the following to package.json:
{
"type": "module",
"scripts": {
"dev": "tsx watch src/server.ts",
"build": "tsup",
"start": "node dist/server.js",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"type-check": "tsc --noEmit --project tsconfig.build.json",
"lint": "eslint",
"lint:fix": "eslint --fix",
"format": "prettier --check .",
"format:fix": "prettier --write .",
"validate": "pnpm type-check && pnpm lint:fix && pnpm format:fix && pnpm test",
"clean": "rm -rf dist coverage"
}
}
Phase 3: Directory Structure
Step 10: Create Directory Structure
mkdir -p src/{controllers,middlewares,repositories/mockdb,routes,schemas,services}
mkdir -p tests/{controllers,middlewares,repositories,routes,schemas,services}
mkdir -p scripts
Phase 4: Core Files
Step 11: Create Environment Config
Create src/env.ts:
import dotenv from "dotenv";
import { z } from "zod";
dotenv.config();
/**
* Environment variable prefix for this service.
* This prevents conflicts when running multiple services in the same environment.
* Change this prefix when creating a new service from this template.
*/
const PREFIX = "BT";
/**
* Helper function to get prefixed environment variable.
* Falls back to unprefixed variable for backwards compatibility during migration.
*/
const getEnv = (name: string): string | undefined => {
return process.env[`${PREFIX}_${name}`] ?? process.env[name];
};
const envSchema = z.object({
NODE_ENV: z.string().default("development"),
PORT: z.coerce.number().default(3000),
});
// Map prefixed environment variables to internal names
const mappedEnv = {
NODE_ENV: getEnv("NODE_ENV"),
PORT: getEnv("PORT"),
};
const _env = envSchema.safeParse(mappedEnv);
if (!_env.success) {
console.error("Invalid environment variables:", _env.error.format());
process.exit(1);
}
export const env = _env.data;
Create .env.example:
# Environment variable prefix: BT (Backend Template) # Change this prefix in src/env.ts when creating a new service BT_NODE_ENV=development BT_PORT=3000
Create .env:
BT_NODE_ENV=development BT_PORT=3000
Step 12: Create App Context Schema
Create src/schemas/app-env.schema.ts:
export interface AppEnv {
Variables: {
validatedBody: unknown;
validatedQuery: unknown;
validatedParams: unknown;
};
}
Step 13: Create App
Create src/app.ts:
import { Hono } from "hono";
import type { AppEnv } from "@/schemas/app-env.schema";
export const app = new Hono<AppEnv>();
app.get("/", (c) => c.text("Hello Hono!"));
Step 14: Create Server
Create src/server.ts:
import { serve } from "@hono/node-server";
import { app } from "@/app";
import { env } from "@/env";
serve(
{
fetch: app.fetch,
port: env.PORT,
},
(info) => {
console.log(`Server is running on http://localhost:${info.port}`);
},
);
Phase 5: Git Configuration
Step 15: Create .gitignore
Create .gitignore:
# dev .yarn/ !.yarn/releases .vscode/* !.vscode/launch.json !.vscode/*.code-snippets !.vscode/extensions.json !.vscode/settings.json .idea/ # deps node_modules/ .pnpm-store/ # env .env .env.production # logs logs/ *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* # misc .DS_Store # Build artifacts dist # Test Coverage coverage
Phase 6: Verification
Step 16: Verify Setup
# Install dependencies (if not already done) pnpm install # Type check pnpm type-check # Lint pnpm lint # Format pnpm format:fix # Start dev server pnpm dev # In another terminal, test the endpoint curl http://localhost:3000 # Should return: Hello Hono!
Files Created Summary
my-backend-service/ ├── src/ │ ├── app.ts # Hono app with Hello World route │ ├── server.ts # Server startup │ ├── env.ts # Environment configuration │ ├── controllers/ # (empty) │ ├── middlewares/ # (empty) │ ├── repositories/ │ │ └── mockdb/ # (empty) │ ├── routes/ # (empty) │ ├── schemas/ │ │ └── app-env.schema.ts # AppEnv interface │ └── services/ # (empty) ├── tests/ │ ├── controllers/ # (empty) │ ├── middlewares/ # (empty) │ ├── repositories/ # (empty) │ ├── routes/ # (empty) │ ├── schemas/ # (empty) │ └── services/ # (empty) ├── scripts/ # (empty) ├── .env ├── .env.example ├── .gitignore ├── .prettierignore ├── eslint.config.ts ├── package.json ├── prettier.config.json ├── tsconfig.json ├── tsconfig.build.json ├── tsup.config.ts └── vitest.config.ts
Next Steps
After bootstrapping, use these skills to build out your application:
- •
setup-errors- Add error handling infrastructure (BaseError, HTTP errors, global handler) - •
setup-events- Add event system for real-time updates (EventEmitter, BaseService) - •
setup-testing- Enhanced test infrastructure (fixtures, helpers) - •
setup-docker- Add Docker support for development and production - •
setup-mongodb- Add MongoDB database support - •
create-resource- Create your first CRUD resource (schema, repository, service, controller, routes)
What NOT to Do
- •Do NOT skip the TypeScript configuration
- •Do NOT use relative imports (always use
@/path alias) - •Do NOT commit
.envfile (only.env.example) - •Do NOT add complex infrastructure here (use dedicated setup skills)
See Also
- •
setup-errors- Error handling infrastructure - •
setup-events- Event-driven architecture - •
setup-testing- Test infrastructure - •
setup-docker- Docker configuration - •
setup-mongodb- MongoDB setup - •
create-resource- Create a complete CRUD resource