How to Get Started with Hono : The Node.js Framework Guide

The growing demand for faster and more modern JavaScript backend frameworks that can handle newer or complex projects led to the creation of Hono. This new and underrated JavaScript backend framework simplifies and boosts performance in projects with its lightweight package size, speed and easier-to-understand syntax.
In this tutorial, you'll learn the basics of Hono, its features, how it is set up, how to build a basic CRUD API for posts, along with testing it using Thunder Client and much more.
Getting Started
To follow along with this tutorial, you need to be familiar with the following:
Basic knowledge of Node.js
Understanding of APIs and CRUD operations
Prior experience with a backend framework like Express.js is preferred, but not necessary.
Feel free to use your favourite code editor and Node.js package manager.
If you also want to check out the article's source code, take a look at this GitHub link.
What is Hono?
Hono is a fast and lightweight JavaScript backend and web application framework used for building robust backend APIs. It includes powerful middlewares, built-in TypeScript support, and works with major JavaScript runtimes.
Why Choose Hono
Here are several cool features that make Hono stand out in a backend project:
Fast and Lightweight: Projects built with Hono are noticeably fast and light, ensuring a smoother developer experience.
Multi-Platform: Hono is compatible with several platforms such as Bun, Node.js, Deno, Cloudflare, etc.
TypeScript Support: Hono offers built-in support for TypeScript. When you create a new Hono app using the create hono command, it automatically sets up the project with TypeScript.
Great Developer Experience: Building projects with Hono is nice because it provides many useful tools while remaining lightweight and fast, giving you a good experience.
Setting Up Hono
To get started with Hono in a project, create a blank project folder and give it any name of your choice:
mkdir hono-app
Next, initialize the folder with the following command:
pnpm init
Hono was built for more modern runtimes like Bun and Deno, but we are using the Node runtime, which normally wouldn’t work with Hono, so for us to get it to run via Node.js, we will need to use a Node.js adapter.
The @hono/node-sever adapter allows you to run Hono applications on Node.js.
Install @hono/node-server adapter with the following command:
pnpm add @hono/node-server
Followed by installing the Hono package into your project folder with the following command:
pnpm add hono@latest
Once Hono is installed, create a new file called main.js and import Hono along with the serve method from the Node.js adapter we installed earlier:
import { serve } from "@hono/node-server";
import { Hono } from "hono";
Now, create a new instance of the Hono class and assign it to a variable called app. Then, call the serve method we imported earlier and add the app variable as its argument:
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
serve(app);
We can configure the serve method to change the server's port number and even display a message in the terminal while the server is running:
serve(
{
port: 4000,
fetch: app.fetch,
},
(info) => {
console.log(`Server Running on PORT:${info.port}`);
}
);
Setting Up Hono with the Create Hono Template
Now, you should be done setting up Hono. However, there’s an easier way to set up Hono, by using the Create Hono template.
To use the Create Hono template, go to your code editor’s terminal and run the following command:
pnpm create hono@latest
This command installs Hono along with its necessary packages like the Node.js adapter, it generates an index.ts file with a sample API after installation.
If you then add a similar code snippet in this index.ts file to what we added to main.js file earlier, everything works identically.
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
serve(
{
port: 4000,
fetch: app.fetch,
},
(info) => {
console.log(`Server Running on PORT:${info.port}`);
}
);
The create Hono template runs Hono out of the box without needing any configurations. Run the following command to spin up the server:
pnpm run dev
This is usually the better way to set up a Hono project, but we will use our old project folder since the create Hono template prioritizes TypeScript for development.
Run the server with the following code:
pnpm start
Your first API route
Hono provides the GET, POST, PUT, and DELETE request methods in the app variable to create all types of API routes. If you're familiar with a backend framework like Express.js, creating an API route is quite similar. However, Hono uses a context object, c, as a parameter in the function for the API route.
A new instance of the Context (c) object is created with every request and is disposed of once the response is returned. You can access Hono's request and response objects, store values in them, and set any headers or status codes you want to return.
Now, create a sample GET request API route with the Context object from the code below:
app.get("/", (c) => {
return c.json({ msg: "Hello Gov'nor" }, 200);
});
Understanding the Context Object
The c parameter, which is called a Context object in Hono, contains several methods in the HonoRequest and HonoResponse object, like request, response, body, json, etc., which you are probably already familiar with from Node.js.
Check out Hono’s documentation to learn more about the Context Object.
Testing out the API request will return the following response:

Basic CRUD in Hono
We will build a basic CRUD Post project to better understand Hono. This involves creating a simple storage using an array to store posts and setting up API routes to create, fetch, update, and delete posts. Later, we'll return the posts array or a specific post as a response when we modify it using an API client like Thunder Client or Postman.
Data Storage
Create a new array called posts with the code below, which will store all the created posts.
let posts = [];
Creating A POST Request API Route
Creating a POST request API route in Hono is similar and straightforward to how it is done in Node.js or many other JavaScript backend frameworks. To create a new POST request, paste the following code:
app.post("/", async (c) => {
let { title, body } = await c.req.parseBody();
if (!title || !body) {
return c.text("Fill in the Title and Body Fields...");
}
const idCount = posts.length + 1;
posts.push({ id: idCount, title, body });
return c.json({ id: idCount, title, body }, 201);
});
Note: Status codes are added in a Hono context object after the route handler has been defined, using the c.status(201) or directly in the responses like this: c.json({ id: idCount, title, body }, 201)
This API route creates new posts and adds them to the posts array we set up earlier. Here's how it works:
Retrieve the title and body from the API client body:
let { title, body } = await c.req.parseBody();
Note: I made this function asynchronous because we retrieved the title and body using the parsed body method in Hono’s request object with the await keyword.
We then check if the title and body fields are filled with the following code:
if (!title || !body) {
return c.text("Fill in the Title and Body Fields...", 400);
}
In a real-world project, we would typically add a new post to a database collection. However, in this tutorial, new posts are added to the posts array.
Push an object to the posts array that includes an id which increases each time a new post is created, along with the title and body variables we retrieved earlier.
posts.push({ id: idCount, title, body });
Note: In Hono, you will need to use a return keyword when calling the context(c) object.
Once you test the API route, it returns a status code of 201 along with the created post, meaning a post has just been created:

Retrieving The Created Posts
Since we just added a POST request API route to create new posts, we also need an API route to view all the created posts. Create a new GET API request method to fetch all the posts from the posts array using the following code:
app.get("/", (c) => {
return c.json(posts, 200);
});
We receive the following response when fetching all the posts after creating a new post:

Retrieving A Post By ID
When you want to perform actions like retrieving a specific post, updating a post, or deleting a post, you will need to include the ID that is gotten from the API route.
Hono provides a request parameter method within the context object(c.req.param()), that can be used to get the post’s ID from an API route.
Create a GET API request method and add the following code along with the Hono context request parameter to get the ID from the API route:
app.get("/:id", (c) => {
const id = c.req.param("id");
if (!id) {
return c.text("ID Not Found!", 404);
}
const post = posts.find((post) => post.id === Number(id));
return c.json(post, 200);
});
Here’s a walkthrough of how to retrieve a post ID and post:
The request parameter you added in the previous code snippet with the argument "id" retrieves the ID from the API route and stores it in a variable called id.
const id = c.req.param("id");
Then we check if the ID exists. If it doesn't, the if statement returns a response with the text “ID Not Found!“.
if (!id) {
return c.text("ID Not Found!", 404);
}
Next, we created a post variable to find the specific post in the posts array using the id variable and finally return the found post as a JSON response:
const post = posts.find((post) => post.id === Number(id));
return c.json(post, 200);
Now, when you try to get an existing post by its ID (number), it returns a response with the following post:

Updating a Post
Updating a post in Hono also requires retrieving the ID from the context request parameter and the PUT API request method. To update a post, paste the following code:
app.put("/:id", async (c) => {
const id = c.req.param("id");
let { title, body } = await c.req.parseBody();
if (!title || !body) {
return c.text("Fill in the Title and Body Fields...", 400);
}
if (!id) {
return c.text("Post Id Not Found!", 404);
}
posts.find((post) => {
if (post.id === Number(id)) {
post.title = title;
post.body = body;
}
});
return c.json({ msg: "Posts Updated!" }, 200);
});
In the code snippet above, we use the find array method on the posts array to retrieve the specific post and update it with the title and body we got earlier:
posts.find((post) => {
if (post.id === Number(id)) {
post.title = title;
post.body = body;
}
});
Note: The ID gotten from the API route is stored in a variable as a string, so we converted it to a number.
Then, finally, return a JSON msg object with a string text of “Posts Updated”:
return c.json({ msg: "Posts Updated!" }, 200);
When you try updating a post, we get the following response:

Deleting a Post
To delete a post in Hono, use the DELETE API request method to find the post by its ID and remove it using the filter array method.
Create a DELETE API request method with the following code:
app.delete("/:id", (c) => {
const id = c.req.param("id");
if (!id) {
return c.text("Post Id Not Found!", 404);
}
posts = posts.filter((post) => post.id !== Number(id));
return c.json({ msg: "Post Deleted!" }, 200);
});
In this code snippet, we reassign the posts array to an array that filters out the post by its ID, returning all the other posts except the one whose ID matches:
posts = posts.filter((post) => post.id !== Number(id));
Finally, we return a JSON msg object with the string text of “Posts Deleted!”:
return c.json({ msg: "Post Deleted!" }, 200);
Once we test out the overall API, everything should work seamlessly

Click here to check out the source code for this project.
Routing and Organising Code
In Hono, API routes, like in every other backend framework, can be split into different files for a more concise codebase. Now, create a new folder called routes along with a new file called post.routes.js.
Then, paste the API routes for Creating a Post, Retrieving a Post by ID, Updating a Post and Deleting a Post into the post.routes.js file, but leave the Get All Posts API route in your main.js file
After pasting the code above, create a new Hono instance in the post.routes.js file and name it postRoute:
let postRoute = new Hono();
Then, change the app instance on the pasted API routes to postRoute:

Next, import the posts array into the post.routes.js file so the API routes can access and modify the posts array:
import { posts } from "../main.js";
Then, export the postRoute instance as a default export:
export default postRoute;
Now, import the post.route.js file from the routes folder into your main.js file with the code below:
import postRoute from "./routes/post.routes.js";
The .route method
Hono provides a .route method that is used to add a route to a Hono instance. Add the API route URL along with the exported route name from the post.routes.js file to the app instance in the main.js file using the code below:
app.route("/", postRoute);
Once you test the API routes again, everything should work identically:

Error Handling
Hono takes a pretty simple approach to handling errors with the following:
If you notice throughout our previous code samples, we checked if certain variables did not exist to return a JSON msg string text as the response. This is a basic but common way of handling errors, in case the variable is undefined:
if (!title || !body) {
return c.text("Fill in the Title and Body Fields...", 400);
}
if (!id) {
return c.text("Post Id Not Found!", 404);
}
That is great for projects. However, we can improve it further by using Hono’s .onError method, which you can attach to a new Hono instance variable with the following code:
app.onError((err, c) => {
console.error(`${err}`)
return c.text('Custom Error Message', 500)
})
app.onError() handles errors and returns a custom response.
Benefits of using Hono
Now that we have explored Hono, we can see how it enhances the developer experience with the following advantages:
Easy-to-understand Syntax: Hono's simple syntax, similar to Express.js, makes migration straightforward or easier to learn for beginners.
Built-in and Custom Middlewares: Hono consists of numerous built-in middlewares, custom middlewares, third-party middlewares and helper functions that can easily be imported to simplify your project
Lightweight: Hono's smaller and more optimised size allows it to handle backend tasks and features more quickly.
Drawbacks to using Hono
Hono offers many benefits, but it also has some drawbacks, such as:
Abstraction: Hono’s wide range of helpful middleware and tools might seem like a high-level abstraction for beginner backend developers.
Adoption: Although Hono is becoming more popular, it is still fairly new in the backend framework world. As a result, developers who specialise in Hono might find fewer job opportunities.
Conclusion
Hono is an underrated backend framework used for building fast and efficient APIs. It features beginner-friendly syntax, a lightweight package size, and provides a great developer experience.
In this article, we explored what Hono is and why we should choose it. Then, we built a basic CRUD API to test it out. If you learned a thing or two about Hono from this article, please like and comment.
Thank You!
Next Steps and Resources
We only covered the basics of Hono due to the scope and goal of this tutorial. While building the Post API, we didn't use a real database or experiment with middlewares and helper functions. If you want to learn more about Hono, you can check out Hono’s Documentation.



