Skip to content

πŸ“ hono boilerplate to run a typescript server using node, bun...

Notifications You must be signed in to change notification settings

marcosrjjunior/hono-boilerplate

Repository files navigation

Hono Boilerplate

Boilerplate for your typescript projects using Hono.

Project Structure
Tech Stack
Requirements
Run Locally
Manage your database using migrations
Run test
FAQ
Dependencies
Extras

Project Structure

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.

Tech Stack

Geral: Hono, Zod, Eslint
Database: Kysely (queries, migrations, types)
Test: Bun test

Requirements

node.js v20+ or bun
nvm installed to manage node versions
pnpm to manage dependencies(npm install -g pnpm)

Run Locally

πŸ“ 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 using pnpm 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

Update your environment variables

Create a .env files from .env.example and populate the values.

cp .env.example .env

Install your dependencies

Nodejs
nvm use
pnpm install
Bun
bun install

Run the project

Nodejs
pnpm node:dev or pnpm dev
Bun
pnpm bun:dev

From here you should be getting a server running on http://localhost:3333

Manage your database using migrations

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

How to write a migration

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.

Run test

Tests are implemented using bun which follows a jest-compatible structure.

pnpm test

Reference: https://bun.sh/docs/cli/test#run-tests

FAQ

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.

Hono best practices
Hono presets

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?

Features

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.

Dependencies

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

Extras

Adding sentry

  • 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)
})