Are you happy with your logging solution? Would you help us out by taking a 30-second survey? Click here


Web server middleware for Dart

Subscribe to updates I use shelf

Statistics on shelf

Number of watchers on Github 70
Number of open issues 15
Average time to close an issue 3 days
Main language Dart
Average time to merge a PR 1 day
Open pull requests 1+
Closed pull requests 7+
Last commit over 1 year ago
Repo Created almost 5 years ago
Repo Last Updated over 1 year ago
Size 261 KB
Homepage https://pub.dartl...
Organization / Authordart-lang
Page Updated
Do you use shelf? Leave a review!
View open issues (15)
View shelf activity
View on github
Fresh, new opensource launches 🚀🚀🚀
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating shelf for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)

Web Server Middleware for Dart

Build Status Coverage Status


Shelf makes it easy to create and compose web servers and parts of web servers. How?

  • Expose a small set of simple types.
  • Map server logic into a simple function: a single argument for the request, the response is the return value.
  • Trivially mix and match synchronous and asynchronous processing.
  • Flexibility to return a simple string or a byte stream with the same model.


See example/example.dart

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;

void main() {
  var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests())

  io.serve(handler, 'localhost', 8080).then((server) {
    print('Serving at http://${}:${server.port}');

shelf.Response _echoRequest(shelf.Request request) {
  return new shelf.Response.ok('Request for "${request.url}"');

Handlers and Middleware

A handler is any function that handles a shelf.Request and returns a shelf.Response. It can either handle the request itself--for example, a static file server that looks up the requested URI on the filesystem--or it can do some processing and forward it to another handler--for example, a logger that prints information about requests and responses to the command line.

The latter kind of handler is called [middleware][], since it sits in the middle of the server stack. Middleware can be thought of as a function that takes a handler and wraps it in another handler to provide additional functionality. A Shelf application is usually composed of many layers of middleware with one or more handlers at the very center; the shelf.Pipeline class makes this sort of application easy to construct.

Some middleware can also take multiple handlers and call one or more of them for each request. For example, a routing middleware might choose which handler to call based on the request's URI or HTTP method, while a cascading middleware might call each one in sequence until one returns a successful response.

Middleware that routes requests between handlers should be sure to update each request's handlerPath and url. This allows inner handlers to know where they are in the application so they can do their own routing correctly. This can be easily accomplished using Request.change():

// In an imaginary routing middleware...
var component = request.url.pathComponents.first;
var handler = _handlers[component];
if (handler == null) return new Response.notFound(null);

// Create a new request just like this one but with whatever URL comes after
// [component] instead.
return handler(request.change(script: component));


An adapter is any code that creates shelf.Request objects, passes them to a handler, and deals with the resulting shelf.Response. For the most part, adapters forward requests from and responses to an underlying HTTP server; shelf_io.serve is this sort of adapter. An adapter might also synthesize HTTP requests within the browser using window.location and window.history, or it might pipe requests directly from an HTTP client to a Shelf handler.

API Requirements

An adapter must handle all errors from the handler, including the handler returning a null response. It should print each error to the console if possible, then act as though the handler returned a 500 response. The adapter may include body data for the 500 response, but this body data must not include information about the error that occurred. This ensures that unexpected errors don't result in exposing internal information in production by default; if the user wants to return detailed error descriptions, they should explicitly include middleware to do so.

An adapter should ensure that asynchronous errors thrown by the handler don't cause the application to crash, even if they aren't reported by the future chain. Specifically, these errors shouldn't be passed to the root zone's error handler; however, if the adapter is run within another error zone, it should allow these errors to be passed to that zone. The following function can be used to capture only errors that would otherwise be top-leveled:

/// Run [callback] and capture any errors that would otherwise be top-leveled.
/// If [this] is called in a non-root error zone, it will just run [callback]
/// and return the result. Otherwise, it will capture any errors using
/// [runZoned] and pass them to [onError].
catchTopLevelErrors(callback(), void onError(error, StackTrace stackTrace)) {
  if (Zone.current.inSameErrorZone(Zone.ROOT)) {
    return runZoned(callback, onError: onError);
  } else {
    return callback();

An adapter that knows its own URL should provide an implementation of the Server interface.

Request Requirements

When implementing an adapter, some rules must be followed. The adapter must not pass the url or handlerPath parameters to new shelf.Request; it should only pass requestedUri. If it passes the context parameter, all keys must begin with the adapter's package name followed by a period. If multiple headers with the same name are received, the adapter must collapse them into a single header separated by commas as per RFC 2616 section 4.2.

If the underlying request uses a chunked transfer coding, the adapter must decode the body before passing it to new shelf.Request and should remove the Transfer-Encoding header. This ensures that message bodies are chunked if and only if the headers declare that they are.

Response Requirements

An adapter must not add or modify any entity headers for a response.

If none of the following conditions are true, the adapter must apply chunked transfer coding to a response's body and set its Transfer-Encoding header to chunked:

  • The status code is less than 200, or equal to 204 or 304.
  • A Content-Length header is provided.
  • The Content-Type header indicates the MIME type multipart/byteranges.
  • The Transfer-Encoding header is set to anything other than identity.

Adapters may find the [addChunkedEncoding()][addChunkedEncoding] middleware useful for implementing this behavior, if the underlying server doesn't implement it manually.

When responding to a HEAD request, the adapter must not emit an entity body. Otherwise, it shouldn't modify the entity body in any way.

An adapter should include information about itself in the Server header of the response by default. If the handler returns a response with the Server header set, that must take precedence over the adapter's default header.

An adapter should include the Date header with the time the handler returns a response. If the handler returns a response with the Date header set, that must take precedence.


shelf open issues Ask a question     (View All Issues)
  • almost 3 years Endless get request starting 0.6.7+1 version
  • about 3 years Move http message to its own package
  • about 4 years Add support for http2
  • over 4 years Add support for multi-valued headers.
  • over 4 years Add access the connection info from HttpRequest
  • over 4 years implement body parsing similar to http_server package
  • over 4 years Implement Cookie() utilities
  • over 4 years convention for logging
  • over 4 years serveRequests should return something that looks like StreamSubscription.cancel
  • over 4 years Request should cope with empty path
  • over 4 years Provide Buffered Request/Response that can be read many times
  • over 4 years Add support for HTTPS
  • over 4 years Support pluggable error logging in shelf_io
shelf open pull requests (View All Pulls)
  • add shared option to serve
shelf questions on Stackoverflow (View All Questions)
  • I want to drag and drop file from download shelf In Mac OS Chrome Browser
  • how to find shelf space optimization for retail store
  • Create a book shelf by using UICollectionView
  • Unable to enable chrome shelf in chrome extension
  • Mercurial shelve extension - how can you view the diff of a shelf?
  • "dyld: Library not loaded" error when using Alamofire in tvOS Top Shelf Extension on device
  • Is there an off the shelf binary format that allows string caching
  • How to get the client IP in a dart shelf-rpc server
  • Dart Server Side: Where are the advantage of using Shelf rather than IO as a Web Server?
  • Is there a good off-the-shelf distributed database solution for Postgres (PostgreSQL)?
  • Get shelf clean version
  • In xcode and tvos, is it possible to convert the top shelf image to an image stack?
  • Play video from Apple TV Top Shelf
  • What is a flexible toolbar in Android, and what is meant by a toolbar launching to "shelf" (mentioned in the Material Design specification)?
  • Invalid Image Asset -Top Shelf Image - must be opaque
  • PHP json parser - off the shelf or roll my own?
  • How do I embed my LibraryThing shelf and Shelfari shelf in Google Sites if I have Dropbox as host?
  • Programmatically Setting Top Shelf Image on tvOS?
  • Where does IntelliJ IDEA store shelf changes on the local drive?
  • Update existing shelf in visual studio
  • Off the shelf programmable USB
  • Sorting cubes on a shelf by moving only 4 cubes to the end of a shelf
  • Non-modular header error for a Top Shelf Extension
  • Off-the-shelf UI component for table-to-table field mapping?
  • Trying to get Mobile Menu Shelf to work
  • incompatibility when running dart rpc and shelf (with shelf_rpc) related to headers which are lists (and not Strings)
  • Incompatibility between the Dart shelf and rpc packages? ('access-control-request-method' header)
  • What is the best practice for supporting different versions of ODP.NET (Oracle.DataAccess.dll) in an off-the-shelf product?
  • move fields into the column shelf of Tableau with out having it "split" the values at the top of the column
  • Change icon on mel script on shelf using mel or python
shelf list of languages used
Other projects in Dart