Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Clojars Project


A simple routing library for ClojureScript that uses Express-like syntax.

Egiak ez ditu bi bide

— A Basque proverb.
Looking for a maintainer.


Add the following dependency to your project.clj file:

[funcool/bide "1.7.0"]

User Guide

Just import the core namespace and start building the router:

(ns myapp.core
  (:require [bide.core :as r]))

(def router
  (r/router [["/api/auth" :myapp/auth]
             ["/api/users/:id" :myapp/user-by-id]]))

Now, you can perform basic operations such as match and resolve:

(r/match router "/api/auth")
;; => [:myapp/auth nil nil]

(r/match router "/api/users/1")
;; => [:myapp/user-by-id {:id "1"} nil]

(r/match router "/api/users/1?foobar=1")
;; => [:myapp/user-by-id {:id "1"} {:foobar "1"}]

(r/match router "/api/other")
;; => nil

(r/resolve router :myapp/auth)
;; => "/api/auth"

(r/resolve router :myapp/user-by-id {:id 2})
;; => "/api/users/2"

(r/resolve router :myapp/user-by-id {:id 2} {:foobar 1})
;; => "/api/users/2?foobar=1"

In addition, you can integrate it in your ClojureScript web application using the provided builtin helpers. It uses goog.History API under the hood:

(defn on-navigate
  "A function which will be called on each route change."
  [name params query]
  (println "Route change to: " name params query))

(r/start! router {:default :myapp/auth
                  :on-navigate on-navigate})

Also, you can pass factory function that returns instance of goog.history.Html5History as value of :html5history key of second argument and bide would use it to manage history events, and/or pass true as value of :html5? key to stop using '#' in URLs.

Note that when :html5? is true, the built-in instance of Html5History uses a custom goog.history.Html5History.TokenTransformer to allow it to handle query parameters. You can construct a transformer with token-transformer.

Finally, you can force the navigation trigger by using the navigate! helper function:

(r/navigate! router :myapp/user-by-id {:id 10})

Or if you don’t want to add entry into history use replace! helper function instead.

How to Contribute?

Just open an issue or PR ;)


Why another routing library?

Existing solutions out there are complex and generally bloated wih irrelevant documentation.

Most libraries work with native Clojure data structures for representing the routing configuration. It’s a great idea, but it does not work very well once your project scales. Things get out of hand pretty fast.

An example of this with bidi routing library:

(def routes
  ["/" [["auth/login" :auth/login]
        [["auth/recovery/token/" :token] :auth/recovery]
        ["workspace/" [[[:project-uuid "/" :page-uuid] :workspace/page]]]]])

The mental effort required to read and understand the configuration defined like this is considerable. Now, let’s see an example using bide:

(def routes
  [["/auth/login" :auth/login]
   ["/auth/recovery/token/:token" :auth/recovery]
   ["/workspace/:project-uuid/:page-uuid" :workspace/page]])

As you can imagine, a simple library like bide does not offer all the features provided by other solutions. New features will be added on-demand. However, we plan to stay as small and simple as possible.

How fast is bide?

Before talking about real performance comparisons and benchmarks, you should know that bide design is very simple and maybe can be considered naive. The worst case for the matching algorithm is O(N) and O(1) for resolve operation.

Considering that having thousands of entries is very unlikely to happen, the match algorithm works pretty well. This is a comparison against the same operations with bidi:

$ node out/benchmarks.js
op=resolve lib=bidi ops=10000
"Elapsed time: 90.989215 msecs"
op=resolve lib=bide ops=10000
"Elapsed time: 19.447844 msecs"
op=match lib=bidi ops=10000
"Elapsed time: 1070.330668 msecs"
op=match lib=bide ops=10000
"Elapsed time: 98.864120 msecs"

I’ve been a bidi user for quite some time, that’s why I choose this library to run the benchmarks.


bide is licensed under BSD (2-Clause) license.