Loading repository data…
Loading repository data…
marcosrjjunior / repository
📝 hono boilerplate to run a typescript server using node, bun...
Boilerplate for your typescript projects using Hono.
Project Structure
Tech Stack
Requirements
Run Locally
Manage your database using migrations
Run test
FAQ
Dependencies
Extras
The main implementation is inside of the /app directory where it uses basic ts node implementation.
/src
/app/cases: # Use cases of your application
/app/repositories: # Repositories and interfaces used by the use cases
/lib/db: # Database structure: migrations, seed, types
/routes: # Routes and middlewares
/tests: # Integration tests
node.ts: # Initial file to run the project using Node
bun.ts: # Initial file to run the project using Bun
Geral: Hono, Zod, Eslint
Database: Kysely (queries, migrations, types)
Test: Bun test
Docs: Scalar
node.js v20+ or bun
nvm installed to manage node versions
pnpm to manage dependencies(npm install -g pnpm)
I recommend using dbngin to spin up an local DB on your machine.
[!NOTE]
If you prefer docker, you can use postgres service from this docker compose
Create your database
CREATE DATABASE project
Create a .env files from .env.example and populate the values.
cp .env.example .env
nvm use
pnpm install
bun install
# Reference: https://bun.sh/docs/install/lockfile
pnpm node:dev or pnpm dev
pnpm bun:dev
From here you should be getting a server running on http://localhost:3333
Migrations are currently defined under lib/db/migrations. An initial migration is already there as an example, adjust to meet your project requirements. Reference
Run all migrations
pnpm db:migrate:up
This command will perform the "up" function for all new migrations
Rollback previous migration
pnpm db:migrate:down
This command will perform the "down" function from previous migration
Run seed
pnpm db:seed
Reset migrations + run seed
pnpm db:reset
To make an update on the database you will need to create a migration
Run the command
pnpm db:migrate:create
This will generate a new file under /lib/db/migrations/DATE-initial.ts
Rename the file to describe what the migration will do e.g DATE-adding_phone_column_to_user.ts
Functions up and down should work.
This project uses kysely-codegen. After running the migration you can re-generate the types using
pnpm db:generate:types
You can find the openapi generated on endpoint "/doc" or access the scalar generated on "/reference".
There is also the "/endpoints" directory that contains endpoints generated to use with bruno. You can use the client or the extension to read them.
Tests are implemented using bun which follows a jest-compatible structure.
# unit tests
pnpm test
pnpm test:integration
Tests also run on pull requests and push to main, check .github/workflows/lint-and-test.yaml
Reference: https://bun.sh/docs/cli/test#run-tests
pnpm node:build
pnpm node:start
pnpm bun:build
pnpm bun:start
This is a matter of personal preference and depends on your application and deployment process.
I've been using this case structure for a while and have found it enjoyable, though I'm still improving and learning as I go.
I often aim for a balanced approach to structure for various reasons.
As a personal recommendation, try not to become too attached to any one framework. You’ll gain more value by focusing on structuring your code and learning about patterns that can benefit your team, projects, and clients.
Feel free to adapt these ideas to fit your needs.
Hono best practices
Hono presets
Thanks to Hono's simplicity, you can structure your project in a way that suits your needs.
The core of this project is located in the /app directory, where I use only JavaScript; none of these files are specific to Hono. This means that if you ever need to switch away from Hono for any reason, you can simply copy the /app directory and adjust the request handling as needed.
Based on my experience with Express.js and Fastify, I’ve found Hono to be powerful, easy to use, and supported by an active community.
Give it a go.
Here are some basic benchmarks (though they’re not particularly significant).
Requests benchmark
Compare benchmark
If you're still not convinced, Fastify is also an excellent option.
Nodejs
To run the project using nodejs, we need some extra dependencies. These are already set in the project.
# dependencies
@hono/node-server
# devDependencies
typescript
tsx
The setup is basically adding the middleware on the initial file.
// ...
import { sentry } from '@hono/sentry'
// ...
app.use(
'*',
sentry({
dsn: process.env.SENTRY_DNS,
tracesSampleRate: isProduction ? 0.2 : 0.8,
environment,
}),
)
Then you can call on your global app.onError
app.onError((error, c) => {
c.get('sentry').captureException(e, {
tags: {}, // any tag
extra: {}, // any extra object
})
return c.json({ error, message: error.message || 'Unknown Error' }, 500)
})