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 app implementation is inside of the /app
directory where it uses basic js node implementation.
"/routes": Routes of the application.
"/lib/db": Database structure. Migrations, seed and types.
"/app/cases": Use cases of your application.
"/app/repositories": Repositores and interfaces that are used by the use cases.
"/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
node.js v20+ or bun
nvm installed to manage node versions
pnpm to manage dependencies(npm install -g pnpm)
π Setup your database
I recommend using dbngin to spin up an local DB on your machine.
[!NOTE]
If you prefer docker, there is also a docker-compose file that you can run that by usingpnpm db:pg
. After the first time, you can simply open your "Docker desktop" or whatever you use to manage docker to start up the service.
Create your database
CREATE DATABASE project
Create a .env
files from .env.example
and populate the values.
cp .env.example .env
Nodejs
nvm use
pnpm install
Bun
bun install
Nodejs
pnpm node:dev or pnpm dev
Bun
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.
Tests are implemented using bun which follows a jest-compatible structure.
pnpm test
Reference: https://bun.sh/docs/cli/test#run-tests
Why this structure?
This is a personal preference, It also depends on your application and how you are deploying.
I've been using this case structure for some time and enjoying but still improving/learning as I go.
I usually try to find the middle term on structural side for various reasons.
Just a personal recommendation, try not get too attached to one framework or another. I believe you can get way more value spending time structuring your code, learning about patterns in a way that can benefit your team, projects, clients.
Again, feel free to adapt to your needs.
Framework agnostic?
Thanks for the simplicity of hono you can basically structure your project in a way that fits your situation.
This core of this project is all under the /app
directory, where I'm using only JS, none of the files there are related to hono. That means, if for some unexpected reason/scenario you need to move away from hono, you can just copy the app directory and make the requests to the cases accordinly.
Bun or node?
Because of this structure I can easily switch between them to test. Based on my situation and project, I'd still recommend to use nodejs.
There is a noticeable delay on requests to s3 using bun still. Github Issue
Last test on: March 07, 2024
It all depends on your project and situation. Bun will probably be more performant and consume less memory, specially on a production environment. The only blocker for me at this point is the one mentioned above, so I still can't tell
I'm mainly using bun to run my tests and it work just fine since it is based on jest.
Why hono?
Coming from previous experiences using express.js and fastify. Hono is powerful, simple to use and has an active community.
Give it a go.
Here are some simple benchmarks (they don't mean much)
Requests benchmark
Compare benchmark
If you still don't buy it, fastify it is also a great 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
ts-node-dev
- For the setup you can use the hono middleware created for that, you can follow the instructions on the readme there.
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)
})