npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@furi-server/furi

v0.14.2

Published

Furi - The Fast HTTP/S Node.js Server Framework

Readme

Furi - Fast HTTP/HTTPS Server framework

Benchmarks 🚀

Furi outperforms both Fastify and Express.js 5.0 in a benchmark test. Below are the benchmarks results.

  1. Number of requests made: 100,000
  2. Total time taken in seconds.
  3. Requests handled in 1 second.

Framework | Requests | Total Time | Requests/Seconds| Built with TypeScript -|-|-|-|- Furi | 100,000 | 11.569 s | 8643.74| ✅ Fastify | 100,000 | 13.847 s | 7221.62| ❌ Express.js v5.0 | 100,000 | 18.020 s | 5549.29| ❌

FEATURE UPDATES 🚨

image sqlite3

  • New embedded Sqlite3 support for in-memory application state management.
  • Minor breaking-change with logger configuration and code refactoring.

Planned work for Sqlite3 and state management. 🎯

  1. Allow state management to persiste on disk.
  2. Add configuration to choose betweek in-memory and disk-based state management.
  3. Add seamless caching support to speed response time for web pages and REST APIs.
  4. Add an application cache store, for custom caching logic and data retrieval.
  5. Add schema support to declare the structure of the application store database table.
  6. Add new accessor methods to allow for flexible types when using the state management system.

Always check the changelog before pulling updates to see what changed. Furi is in early preview mode, so expect rapid changes, some breaking.

A Return to Simplicity ✅

Furi is a Node.js framework coded in TypeScript. If you love TypeScript, you will feel at home coding with Furi. If you love plain JavaScript, you will love coding in Furi, you get to decide.

The design has been kept as close to the Node.js API without using external dependencies. Coded using modern JavaScript and the latest Node.js APIs.

The Router was coded from the ground up in TypeScript, it is the core of the framework, with a blazing fast lookup and matching algorithm.

Zero useless abstraction, simple clean coding, designed for hardware with small resources. Perfect for micro-architecture. Very little between your code and the Node.js API to minimize performance overhead.

Router has been battle tested with unit tests and functional tests.

A self contained design and zero external dependencies means there is less surface area for bugs and security issues to hide and creep in. There is less likelihood for working code to break after pulling in updates. Having to maintain perfect working code broken due to an update is an anti-pattern and an insane mindset to develop software.

Furi will keep simple things simple and make hard things easier without breaking your working code. It is however still in the early preview stage so expect changes as I explore design ideas.

Furi is currently under active development. However it is feature complete with respect to the Router, and today could be put into production use. Current development effort is focused on adding support for a easy to use State management store for seamless data access. Persistence using SQLite3 as the default "embedded" database engine, with a plug-in architecture for other DB engines.

BOM - Bill of Material

The following tools, technologies and software was used in the development of Furi (v0.1.4).

Item | Version | Description --- | --- | --- TypeScript | 5.8.3 | A superset of JavaScript that adds static typing and other features to the language. node | 22 LTS | Node.js core APIs. yaml | 2.7.1 | A library for parsing YAML used to read FURI configuration file. better-sqlite3 | 7.6.13 | A library for interacting with SQLite databases. Linux | 6.13.1-1-default | openSUSE Tumbleweed with KDE desktop

NOTE: See Changelog for additional details on changes and updates. ✅

Example source code

You can find example source code at the GitHib furi-examples repository.

You can download the example source use using git:

git clone https://github.com/rajinder-yadav/furi-examples.git

The examples are easy to follow and should give you to a good understanding of how to use the Furi framework.

For more the Typescript examples and can install and use Deno. The first example in directory, "01-simple-js-node" shows you how to use Node.js with plain JavaScript. The examples are number to help you quick start from basic and move to advanced usage.

Coding with JavaScript

File: "main.js"

import { Furi } from '@furi-server/furi';
const furi = Furi.create();

furi.get('/', (ctx) => {
    return { message: 'Hello World' };
});

furi.start();

Coding with TypeScript

You can use TypeScript with Node.js, but you will need to compile the TypeScript code to JavaScript before running it with Node.js.

With Deno it is simpler, as it will run the TypeScript code without needing a separate compile step.

File: "main.ts"

import { Furi, ApplicationContext } from '@furi-server/furi';
const furi = Furi.create();

furi.get('/', (ctx: ApplicationContext) => {
    return { message: 'Hello World' };
});

furi.start();

Using NPM and Node.js

To install the NPM package, use:

npm install @furi-server/furi

Using Deno

If you are using Deno, add the package with:

deno add npm:@furi-server/furi

Startup message

When you run the server application, you will see a similar output in your terminal:

INFO, Furi::listen Creating a unsecure HTTP server.
INFO, Furi Server (v0.14.0) started.
INFO, Server  { mode: http, host: localhost, port: 3030, env: development }
INFO, Runtime { node: 22.14.0, v8: 12.4.254.21-node.22 }
INFO, Logger  { enable: true, level: INFO, logFile: ./logs/furi.log, mode: stream, flushPeriod: 1000ms, maxCount: 100, rollover: 24h }

This can help you quickly identify that your server is running, configuration settings and the runtime environment details.

Declare a named route

The code below shows how to declare a named route, and also how to read the named route parameters from the handler function, using the ApplicationContext object.

furi.get("/about/:user_id", (ctx: ApplicationContext) => {

  ctx.response.writeHead(200, {
    "Content-Type": "text/html",
    "User-Agent": USER_AGENT
  });

  ctx.end(`<p>User page for: ${ctx.request.params.user_id}</p>\n`);
});

Use a router to declare routes

Below we declare a route handler on a router, then we mouth the router to the Furi instance.

const furi = Furi.create();
const router = Furi.router();

router.get('/home', (ctx: ApplicationContext) => {
  ctx.response.writeHead(200, {
    'Content-Type': 'text/html',
    'User-Agent': USER_AGENT
  });
  ctx.send('<h1>Home Page</h1>\n');
  ctx.send('<p>Welcome to the home page.</p>\n');
  ctx.end();
});

furi.use(router);

Mounting to a route path:

This will mount the router to the "/v1/api" path. The "/home" route will be accessible at "/v1/api/home".

furi.use('/v1/api', router);

Mounting top-level middlewares

You can mount top-level middlewares to the Furi instance. These middlewares will be executed for every request.

  1. A top-level middleware is mounted using "use()" method.
  2. The handler function take two arguments:
    • Application context object.
    • Next function to call the next middleware or handler.

NOTE: The last handler function must end the request with a call to "end()", or returning a value.

router.use((ctx: ApplicationContext, next: Middleware) => {
  ctx.send('Top-level Middleware 1\n');
  next();
});
router.use((ctx: ApplicationContext, next: Middleware) => {
  ctx.send('Top-level Middleware 2\n');
  next();
});

Declaring route based middlewares

router.get('/home', (ctx: ApplicationContext, next: Middleware) => {
  ctx.send('Middleware 1\n');
  next();
});
router.get('/home', (ctx: ApplicationContext, next: Middleware) => {
  ctx.send('Middleware 2\n');
  next();
});
router.get('/home', (ctx: ApplicationContext, next: Middleware) => {
  ctx.send('<h1>Home Page</h1>\n');
  ctx.end('<p>Welcome to the home page.</p>\n');
});

Supported middlewares

Furi currently support the following core middlewares:

  1. Body parser
  2. Cors
  3. Web

Documentation forth coming once I have time to write it.

Array based routing

Furi now supports array based routes. You declare one or more routes in the "routes" array.

Each route entry requires three properties:

  1. method
  2. path
  3. controller

NOTE: the "controller" property can be a single handler function, or multiple handlers declared inside the "controller" array. See: Declaring route-level middleware.

Here is an example of a route with an inline lambda handler:

import { Furi } from '@furi-server/furi';
const furi = Furi.create();

const routes: Routes = {
  routes: [
    {
      method: 'get',
      path: '/one',
      controller: (ctx: ApplicationContext, next: Middleware) => {
        ctx.response.writeHead(200, {
          'Content-Type': 'text/html',
          'User-Agent': USER_AGENT
        });
        ctx.end('Middleware Pre!\n');
      }
    }
  ]
}

furi.use(routes);

You can also mount the array route on a path:

furi.use('/v1/api', routes);

You can also mount the array on a router and then mount that to the app:

const router = Furi.router();
router.use(routes);

furi.use('/admin',router);

NOTE: Top-level middlewares, even when mounted to a router, that are then mounted to the route-path will always remain top-level middlewares. Array based middleware routes are declared further below.

Declaring a Handler Class

To declare the class based handler, you will need to:

  1. Subclass "BaseRouterHandler".
  2. Override the "handle()" method.

NOTE: You can also declare a class based middleware, the handler function will also need to accept the "next" argument.

class HelloWordHandler extends BaseRouterHandler {

   override handle(ctx: ApplicationContext): any {
        ctx.response.writeHead(200, {
            'Content-Type': 'text/plain',
            'User-Agent': USER_AGENT
        });
        // ctx.end('HelloWordHandler\n');
        return 'HelloWordHandler\n';
    }
}

In the router array, you simply pass the class name to the controller property:

const routes: Routes = {
  routes: [
    {
      method: 'get',
      path: '/helloworld',
      controller: HelloWordMiddlewareHandler
    }
  ]
};

const router = Furi.router();
router.use(routes);

Declaring top-level middleware

Remember will middleware, from the handler function you will need to call "next()" to pass control to the next middleware or handler.

function myMiddleware(ctx: ApplicationContext, next: Middleware) {
  ctx.response.writeHead(200, {
    'Content-Type': 'text/html',
    'User-Agent': USER_AGENT
  });
  ctx.send('Middleware Pre!\n');
  next();
}

In the router array, the top-level middlewares are declared in the middleware array:

const routes: Routes = {
  middleware: [
    myMiddleware
  ],
  routes: [
    ...
  ]
};

Declaring route-level middleware

As with the function based routes, you can also declare route-level middleware in route array:

const routes: Routes = {
  routes: [
    {
      method: 'get',
      path: '/one',
      controller: (ctx: ApplicationContext, next: Middleware) => {
        ctx.response.writeHead(200, {
          'Content-Type': 'text/html',
          'User-Agent': USER_AGENT
        });
        ctx.send('Middleware Pre!\n');
        next();
      }
    },
    {
      method: 'get',
      path: '/one',
      controller: (ctx: ApplicationContext, next: Middleware) => {
        ctx.response.writeHead(200, {
          'Content-Type': 'text/html',
          'User-Agent': USER_AGENT
        });
        ctx.end('Hello World!\n');
      }
    },
  ]
};

Since you are declaring multiple route handlers on the same route, you can simplify the declaration. Just combine the handler functions in the "controller" array, like this:

const routes: Routes = {
  routes: [
    {
      method: 'get',
      path: '/one',
      controller: [
        (ctx: ApplicationContext, next: Middleware) => {
          ctx.response.writeHead(200, {
            'Content-Type': 'text/html',
            'User-Agent': USER_AGENT
          });
          ctx.send('Middleware Pre!\n');
          next();
        },
        (ctx: ApplicationContext, next: Middleware) => {
          ctx.response.writeHead(200, {
            'Content-Type': 'text/html',
            'User-Agent': USER_AGENT
          });
          ctx.end('Hello World!\n');
        }
      ]
    },
  ]
};

Server Configuration file

Furi lets you configure server settings from a YAML file. This allows you to easily change settings without having to modify your code.

Currently the configurable setting can control. All these settings are optional.

  1. Server start up properties.
  2. Logging properties.
  3. HTTPS properties.

Configuration file

The server configuration must be called, "furi.yaml" or "furi.yml" and placed under the project root directory.

If you configuration file is found, Furi will use sensible defaults.

File: "furi.yaml" (optional)

Server properties

This configuration control the server startup properties.

server:
  port: 3030
  host: localhost
  env: development

Super fast stream logging ⚡

Furi supports fist-class logging at the core. Logging is fast and takes place on a background worker-thread, so the main thread never blocks. Logging can be buffered, or immediately written to file. Logging behavior can be configured in Furi's configuration YAML file.

Logging uses the latest Node.js features. Since logging is the core functionality of Furi, there is very little code overhead compared to existing logging libraries.

Note file logging is disabled by default, you must enable it in Furi YAML configuration file.

Logger configuration

Here are the configurable logging options:

  • enable: Turn logging on or off.
  • flushPeriod: Control time to flush buffered log messages.
  • maxCount: Maximum number of log messages before flushing.
  • mode: Can be one of "stream" or "buffer".
  • level: Can be one of "debug", "info", "log", "warn", "error", "critical" or "fatal".
  • logDir: Log directory, will be created if it does not exist.
  • logFile: Log filename.
  • rollover: Maximum number of days before log file is rolled over.

The level is used to filter log messages based on their severity. Only messages at or above the configured level will be logged.

If you do not declare any logger settings, the following are the default setting values:

logger:
  enable: false
  flushPeriod: 1000
  logDir: logs
  logFile: furi.log
  maxCount: 100
  mode: buffer
  level: info
  rollover: 24

To enable logging you only need to change one setting:

logger:
  enable: true

This will result in buffered logging, if you want to view immediate logging, you can switch to stream mode:

logger:
  enable: true
  mode: stream

Log levels

It is suggested for Users application code, you log at the "log" level. The framework logs at the "info" level, to provide additional information on the request. However should you ever want to limit logging to your own application code while developing, it will help reduce the log noise.

The following log levels are supported, list in increasing order of severity:

Level | Description ------|------------- debug | Verbose output for debugging purposes. info | Default log, details operations information. log | General User application level logging. warn | State that is not a normal operation. error | Application level error needing investigation. critical | System level error that may cause application to fail. fatal | Unrecoverable error causing application to terminate.

Enabling HTTPS Support

Furi makes it easy to spin-up a HTTPS server. You do not need to code this up manually in your server application code.

Furi is started with HTTPS support by providing the path to the SSL key and certificate files in the"furi.yaml" server configuration file.

You must declare the properties under the "cert" section as follows:

Using a SSL certificate

Here is how you would start Furi with HTTPS:

cert:
  key: ./ssl/key.pem
  cert: ./ssl/cert.pem

Using a SSL certificate with a passphrase

cert:
  key:  ./ssl/key.pem
  cert: ./ssl/cert.pem
  passphrase: hello123

When Furi is running under HTTPS, it will shows in the log and startup message. You will see "__mode: https" under Server.

Furi Server (v0.14.0) started.
Server  { mode: http, host: localhost, port: 3030, env: development }
Runtime { deno: 2.2.5, v8: 13.5.212.4-rusty, typescript: 5.7.3 }
Logger  { enable: true, level: INFO, logFile: ./logs/furi.log, mode: stream, flushPeriod: 1000ms, maxCount: 100, rollover: 24h }

Sample log output

2025-03-23T04:11:05.018Z, INFO, Furi::listen Creating a unsecure HTTP server.
2025-03-23T04:11:05.019Z, INFO, Furi Server (v0.13.3) started.
2025-03-23T04:11:05.019Z, INFO, Server  { mode: http, host: localhost, port: 3030, env: development }
2025-03-23T04:11:05.019Z, INFO, Runtime { deno: 2.2.5, v8: 13.5.212.4-rusty, typescript: 5.7.3 }
2025-03-23T04:11:05.020Z, INFO, Logger  { enable: true, level: INFO, logFile: furi.log, mode: stream, flushPeriod: 1000ms, maxCount: 100 }
2025-03-23T04:11:09.343Z, INFO, host: localhost:3030, remote-ip: 127.0.0.1, remote-port: 60452, http: 1.1, method: GET, url: /
2025-03-23T04:11:09.363Z, INFO, host: localhost:3030, remote-ip: 127.0.0.1, remote-port: 60466, http: 1.1, method: GET, url: /
2025-03-23T04:11:09.368Z, INFO, host: localhost:3030, remote-ip: 127.0.0.1, remote-port: 60478, http: 1.1, method: GET, url: /about
2025-03-23T04:11:09.373Z, INFO, host: localhost:3030, remote-ip: 127.0.0.1, remote-port: 60488, http: 1.1, method: GET, url: /about/
2025-03-23T04:11:09.377Z, INFO, host: localhost:3030, remote-ip: 127.0.0.1, remote-port: 60504, http: 1.1, method: GET, url: /about/raj12

Motivation

Image

The primary objective of the Furi project is to provide a fast, small HTTP server that runs on small hardware with low memory. This benefits micro-architect environments with scaling and performance, with faster load time, compact footprint to maximize bigger production workloads.

The guiding principle of the project is to have the code base self contain with no external dependencies. This allows for easy deployment and maintenance on any platform that supports Node.js. The aim is for small independent shops to be able to run a production server and website while keeping the cost down substantially, along with the effort to maintain the setup.

Why

A fast, responsive and lightweight framework that is easy to use. Furi keeps your code simple, avoids useless abstraction and does not get in the way with working with Node.js core APIs should you ever need to.

Inspired by Express.js and Koa.

Benchmarks 🚀

Furi outperformed both Fastify and Express.js 5.0 in a benchmark test. Below are the benchmarks results.

  1. Number of requests made: 100,000
  2. Total time taken in seconds.
  3. Requests handled in 1 second.

Framework | Requests | Total Time | Requests/Seconds| Built with TypeScript -|-|-|-|- Furi | 100,000 | 11.569 s | 8643.74| ✅ Fastify | 100,000 | 13.847 s | 7221.62| ❌ Express.js v5.0 | 100,000 | 18.020 s | 5549.29| ❌

Furi Benchmark

Furi

Fastify Benchmark

Fastify

Express Benchmark

Express