PHPackages                             8ctopus/nano-router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. 8ctopus/nano-router

ActiveLibrary[HTTP &amp; Networking](/categories/http)

8ctopus/nano-router
===================

An experimental PSR-7, PSR-17 router

14.1.1(5mo ago)1288MITPHPPHP &gt;=8.1CI passing

Since Apr 25Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/8ctopus/nano-router)[ Packagist](https://packagist.org/packages/8ctopus/nano-router)[ Docs](https://github.com/8ctopus/nano-router)[ RSS](/packages/8ctopus-nano-router/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (10)Versions (46)Used By (0)

nano router
===========

[](#nano-router)

[![packagist](https://camo.githubusercontent.com/af0cd3bfade9d8424e1f0c4fe74146bfac67ab74bb9945c94179837080456df5/68747470733a2f2f706f7365722e707567782e6f72672f3863746f7075732f6e616e6f2d726f757465722f76)](https://packagist.org/packages/8ctopus/nano-router)[![downloads](https://camo.githubusercontent.com/327f3654f221b9e02a5af5da8caae3d8c86862a9662aafebbec233587c4b0179/68747470733a2f2f706f7365722e707567782e6f72672f3863746f7075732f6e616e6f2d726f757465722f646f776e6c6f616473)](https://packagist.org/packages/8ctopus/nano-router)[![min php version](https://camo.githubusercontent.com/5b8568ae8e12383077e9e34c5de70ad1ade44436335240fd844dbf51582600f8/68747470733a2f2f706f7365722e707567782e6f72672f3863746f7075732f6e616e6f2d726f757465722f726571756972652f706870)](https://packagist.org/packages/8ctopus/nano-router)[![license](https://camo.githubusercontent.com/e05e752d961acf22492d3b44c8943b4fd32916e96af9702481c1358771c956b1/68747470733a2f2f706f7365722e707567782e6f72672f3863746f7075732f6e616e6f2d726f757465722f6c6963656e7365)](https://packagist.org/packages/8ctopus/nano-router)[![tests](https://github.com/8ctopus/nano-router/actions/workflows/tests.yml/badge.svg)](https://github.com/8ctopus/nano-router/actions/workflows/tests.yml)[![code coverage badge](https://raw.githubusercontent.com/8ctopus/nano-router/image-data/coverage.svg)](https://raw.githubusercontent.com/8ctopus/nano-router/image-data/coverage.svg)[![lines of code](https://raw.githubusercontent.com/8ctopus/nano-router/image-data/lines.svg)](https://raw.githubusercontent.com/8ctopus/nano-router/image-data/lines.svg)

An experimental PSR-7, PSR-17 router

features
--------

[](#features)

- very fast (less than 2ms on simple routing)
- uses PSR-7 and PSR-17 standards
- no dependencies besides PSR-7/17

While I consider it still experimental, I have been using it in production to host [legend.octopuslabs.io](https://legend.octopuslabs.io/) without any issues so far.

introduction for beginners
--------------------------

[](#introduction-for-beginners)

The purpose of a router is to match a user (client) http request to a specific function that will handle the user request and deliver a response to the client.

[PSR-7](https://www.php-fig.org/psr/psr-7/) defines the request and response interfaces, while [PSR-17](https://www.php-fig.org/psr/psr-17/) defines the factories for creating them. In other words, factories are used to create the request and response objects.

Here's some pseudo-code that explains the concept:

```
$router = new Router();

// add route
$router->addRoute(new Route(RouteType::Exact, 'GET', '/test.php', function (ServerRequestInterface $request) : ResponseInterface {
    return new Response(200, ['Content-Type' => 'text/plain'], 'You\'ve reached the test page');
}));

// create user http request
$request = ServerRequestCreator::createFromGlobals($_SERVER, $_FILES, $_COOKIE, $_GET, $_POST);

// resolve finds the function that handles the user request, calls it and returns its response
$response = $router->resolve($request);

// send response to client (echoes internally)
(new SapiEmitter())
    ->emit($response);
```

demo
----

[](#demo)

To play with the demo, clone the repo, run `php -S localhost:80 demo/public/index.php -t demo/public/` and open your browser at `http://localhost`. Alternatively you can run the demo within a Docker container `docker-compose up &`.

install
-------

[](#install)

- `composer require 8ctopus/nano-router`
- if you don't have any preference for the PSR-7 implementation, install [HttpSoft](https://github.com/httpsoft) `composer require httpsoft/http-message httpsoft/http-emitter`
- redirect all traffic (except existing files) to the router in `.htaccess` for those using Apache

```
RewriteEngine on

# redirect all not existing files and directories to router
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [END]
```

and for nginx (untested)

```
location / {
    try_files $uri $uri/ /index.php$is_args$args;
}
```

- create `index.php`

```
use Oct8pus\NanoRouter\NanoRouter;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

// use any PSR-7, PSR-17 implementations, here HttpSoft
use HttpSoft\Emitter\SapiEmitter;
use HttpSoft\Message\Response;
use HttpSoft\Message\ServerRequestFactory;
use HttpSoft\Message\Stream;
use HttpSoft\ServerRequest\ServerRequestCreator;

require_once __DIR__ . '/vendor/autoload.php';

$router = new NanoRouter(Response::class, ServerRequestFactory::class);

$router
    // add simple route
    ->addRoute(new Route(RouteType::Exact, 'GET', '/test.php', function (ServerRequestInterface $request) : ResponseInterface {
        $stream = new Stream();
        $stream->write('test.php');

        return new Response(200, [], $stream);
    }))
    // add starts with route
    ->addRoute(new Route(RouteType::StartsWith, ['GET', 'POST'], '/test/', function (ServerRequestInterface $request) : ResponseInterface {
        $stream = new Stream();
        $stream->write('request target - '. $request->getRequestTarget());

        return new Response(200, [], $stream);
    }))
    // add regex route
    ->addRoute(new Route(RouteType::Regex, '*', '~/php(.*)/~', function (ServerRequestInterface $request) : ResponseInterface {
        $stream = new Stream();
        $stream->write('request target - '. $request->getRequestTarget());

        return new Response(200, [], $stream);
    }))
    ->addErrorHandler(404, function (ServerRequestInterface $request) : ResponseInterface {
        $stream = new Stream();
        $stream->write('page not found - ' . $request->getRequestTarget());

        return new Response(404, [], $stream);
    })
    ->addMiddleware('*', '~(.*)~', MiddlewareType::Post, function (ResponseInterface $response, ServerRequestInterface $request) : ResponseInterface {
        return $response->withHeader('X-Powered-By', '8ctopus');
    });

// create request from globals
$request = ServerRequestCreator::createFromGlobals($_SERVER, $_FILES, $_COOKIE, $_GET, $_POST);

// resolve request into a response
$response = $router->resolve($request);

// send response to client
(new SapiEmitter())
    ->emit($response);
```

exception handling
------------------

[](#exception-handling)

By default, `Throwable`, and everything inherited from it such as `Exception`, are caught by the router provided the exception occurs within the route code. That functionality can be disabled in the constructor by setting it to `false`.

```
new NanoRouter(Response::class, ServerRequestFactory::class, false, false);
```

The `RouteException` class offers an elegant way to deal with http errors such as `404`, `401`, `429`, .... The router will automatically catch the exception and return the appropriate response to the client.

```
throw new RouteException('page not found', 404);

// client sees 404 page
```

advanced functionalities
------------------------

[](#advanced-functionalities)

There is more to it, it's just not in the readme yet, most of it can be experimented within the demo, such as:

- pre and post middleware

run tests
---------

[](#run-tests)

```
composer test

```

clean code
----------

[](#clean-code)

```
composer fix(-risky)

```

todo ideas
----------

[](#todo-ideas)

- add basePath
- class wrapper for subroutes
- should pre middleware only work on valid requests? now not valid routes are still going through the middleware probably we need both
- add starts with middleware
- check psr-15 middleware
- how to easily route inside class?

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance71

Regular maintenance activity

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity70

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~30 days

Recently: every ~94 days

Total

44

Last Release

163d ago

Major Versions

9.0.2 → 10.0.02024-02-01

10.0.1 → 11.0.02024-02-26

11.0.0 → 12.0.02024-02-28

12.0.0 → 13.0.02024-08-07

13.1.1 → 14.0.02024-11-15

PHP version history (3 changes)0.3.1PHP &gt;=7.0

0.3.3PHP &gt;=7.4

5.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/4dafd5f7ef8134a5c9b231686c5da3d6416db09139b45aac0b26952178dffb8a?d=identicon)[8ctopus](/maintainers/8ctopus)

---

Top Contributors

[![8ctopus](https://avatars.githubusercontent.com/u/13252042?v=4)](https://github.com/8ctopus "8ctopus (271 commits)")

---

Tags

phppsr-17psr-7routerpsr-7psr-17router

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/8ctopus-nano-router/health.svg)

```
[![Health](https://phpackages.com/badges/8ctopus-nano-router/health.svg)](https://phpackages.com/packages/8ctopus-nano-router)
```

###  Alternatives

[psr/http-factory

PSR-17: Common interfaces for PSR-7 HTTP message factories

1.9k692.9M1.9k](/packages/psr-http-factory)[symfony/psr-http-message-bridge

PSR HTTP message bridge

1.3k296.6M804](/packages/symfony-psr-http-message-bridge)[nyholm/psr7

A fast PHP7 implementation of PSR-7

1.3k235.4M2.4k](/packages/nyholm-psr7)[laminas/laminas-diactoros

PSR HTTP Message implementations

546105.8M962](/packages/laminas-laminas-diactoros)[league/route

Fast routing and dispatch component including PSR-15 middleware, built on top of FastRoute.

6633.1M116](/packages/league-route)[aura/router

Powerful, flexible web routing for PSR-7 requests.

5231.5M67](/packages/aura-router)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
