Find file
Fetching contributors…
Cannot retrieve contributors at this time
604 lines (421 sloc) 18.5 KB


PSGI - Perl Web Server Gateway Interface Specification


This document specifies a standard interface between web servers and Perl web applications or frameworks. This interface is designed to promote web application portability and reduce the duplication of effort by web application framework developers.

Please keep in mind that PSGI is not Yet Another web application framework. PSGI is a specification to decouple web server environments from web application framework code. Nor is PSGI a web application API. Web application developers (end users) will not run their web applications directly using the PSGI interface, but instead are encouraged to use frameworks that support PSGI. There is also a reference PSGI implementation called Plack.



A Server is a web server that accepts HTTP requests, dispatches the request to web applications, and returns the HTTP response to the client. In the context of PSGI the server could be a Perl process running inside an HTTP server (e.g. mod_perl in Apache), a daemon process called from a web server (e.g. FastCGI daemon) or a pure perl HTTP server.

Servers are also called PSGI implementations as well as Backends.


Applications are web applications that accept an HTTP request and return an HTTP response. In PSGI an application is a code reference.


Middleware is a PSGI application (a code reference) and a Server. Middleware looks like an application when called from a server, and it in turn can call other applications. It can be thought of a plugin to extend a PSGI application.

Framework developers

Framework developers are the authors of web application frameworks. They write adapters (or engines) which accept PSGI input, run a web application, and return a PSGI response to the server.

Web application developers

Web application developers are developers who write code on top of a web application framework. These developers should never have to deal with PSGI directly.



A PSGI application is a Perl code reference. It takes exactly one argument, the environment, and returns an array reference containing exactly three values.

sub app {
    my $env = shift;
    return [
        [ 'Content-Type' => 'text/plain' ],
        [ "Hello World" ], # or IO::Handle-like object

The Environment

The environment MUST be a hash reference that includes CGI-like headers, as detailed below. The application is free to modify the environment. The environment MUST include these keys (adopted from PEP 333, Rack and JSGI) except when they would normally be empty.

When an environment key is described as a boolean, its value MUST conform to Perl's notion of boolean-ness. This means that an empty string or an explicit 0 are both valid false values. If a boolean key is not present, an application MUST treat this as a false value.

The values for all CGI keys (named without a period) MUST be a scalar string.

See below for details.

  • REQUEST_METHOD: The HTTP request method, such as "GET" or "POST". This MUST NOT be an empty string, and so is always required.

  • SCRIPT_NAME: The initial portion of the request URL's path, corresponding to the application. This tells the application its virtual "location". This may be an empty string if the application corresponds to the server's root URI.

    If this key is not empty, it MUST start with a forward slash (/).

  • PATH_INFO: The remainder of the request URL's path, designating the virtual "location" of the request's target within the application. This may be an empty string if the request URL targets the application root and does not have a trailing slash. This value should be URI decoded by servers in order to be compatible with RFC 3875.

    If this key is not empty, it MUST start with a forward slash (/).

  • REQUEST_URI: The undecoded, raw request URL line. It is the raw URI path and query part that appears in the HTTP GET /... HTTP/1.x line and doesn't contain URI scheme and host names.

    Unlike PATH_INFO, this value SHOULD NOT be decoded by servers. It is an application's responsibility to properly decode paths in order to map URLs to application handlers if they choose to use this key instead of PATH_INFO.

  • QUERY_STRING: The portion of the request URL that follows the ?, if any. This key MAY be empty, but MUST always be present, even if empty.

  • SERVER_NAME, SERVER_PORT: When combined with SCRIPT_NAME and PATH_INFO, these keys can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to SERVER_NAME for reconstructing the request URL. SERVER_NAME and SERVER_PORT MUST NOT be empty strings, and are always required.

  • SERVER_PROTOCOL: The version of the protocol the client used to send the request. Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the application to determine how to treat any HTTP request headers.

  • CONTENT_LENGTH: The length of the content in bytes, as an integer. This key MAY be omitted.

  • CONTENT_TYPE: The request's MIME type, as specified by the client. This key MAY be omitted.

  • HTTP_* Keys: These keys correspond to the client-supplied HTTP request headers. The presence or absence of these keys should correspond to the presence or absence of the appropriate HTTP header in the request.

    If there are multiple header lines sent with the same key, the server should treat them as if they were sent in one line and combine them with , , as in RFC 2616.

In addition to the keys above, the PSGI environment MUST also include these PSGI-specific keys:

  • psgi.version: An array reference [1,0] representing this version of PSGI. The first number is the major version and the second it the minor version.

  • psgi.url_scheme: A string http or https, depending on the request URL.

  • psgi.input: the input stream. See below for details.

  • psgi.errors: the error stream. See below for details.

  • psgi.multithread: This is a boolean value, which MUST be true if the application may be simultaneously invoked by another thread in the same process, false otherwise.

  • psgi.multiprocess: This is a boolean value, which MUST be true if an equivalent application object may be simultaneously invoked by another process, false otherwise.

The PSGI environment MAY also include these optional PSGI keys:

  • psgi.run_once: A boolean which is true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar).

  • psgi.nonblocking: A boolean which is true if the server is calling the application in an non-blocking event loop.

  • psgi.streaming: A boolean which is true if the server supports callback style delayed response and streaming writer object.

The server or the application can store its own data in the environment as well. These keys MUST contain at least one dot, and SHOULD be prefixed uniquely. The psgi. prefix is reserved for use with the PSGI core implementation and officially blessed extensions. This prefix MUST NOT be used by other servers or application.

The environment MUST NOT contain keys named HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH.

One of SCRIPT_NAME or PATH_INFO MUST be set. PATH_INFO should be / if SCRIPT_NAME is empty. SCRIPT_NAME MUST NOT be /, but MAY be empty.

The Input Stream

The input stream in psgi.input is an IO::Handle-like object which streams the raw HTTP POST or PUT data. If it is a file handle then it MUST be opened in binary mode. The input stream MUST respond to read and MAY implement seek.

Perl's built-in filehandles or IO::Handle based objects should work as-is in a PSGI server. Application developers SHOULD NOT inspect the type or class of the stream. Instead, they SHOULD simply call read on the object.

Application developers SHOULD NOT use Perl's built-in read or iterator (<$fh>) to read from the input stream. Instead, application developers should call read as a method ($fh->read) to allow for duck typing.

Framework developers, if they know the input stream will be used with the built-in read() in any upstream code they can't touch, SHOULD use PerlIO or a tied handle to work around with this problem.

The input stream objet is expected to provide a read method:

$input->read($buf, $len [, $offset ]);

Returns the number of characters actually read, 0 at end of file, or undef if there was an error.

It may also implement an optional seek method.

$input->seek($pos, $whence);

Returns 1 on success, 0 otherwise.

See the IO::Handle documentation for more details on exactly how these methods should work.

The Error Stream

The error stream in psgi.errors is an IO::Handle-like object to print errors. The error stream must implement a print method.

As with the input stream, Perl's built-in filehandles or IO::Handle based objects should work as-is in a PSGI server. Application developers SHOULD NOT inspect the type or class of the stream. Instead, they SHOULD simply call print on the object.


Returns true if successful.

The Response

Applications MUST return a response as a three element array reference.

IF the server supports the streaming (see below), an application MAY choose to return other type of responses such as a code reference to delay the response.

The response array reference consists of the following elements:


An HTTP status code. This MUST be an integer greater than or equal to 100, and SHOULD be an HTTP status code as documented in RFC 2616.


The headers MUST be an array reference (not a hash reference) of key/value pairs. This means it MUST contain an even number of elements.

The header MUST NOT contain a key named Status, onr any keys with : or newlines in their name. It MUST NOT contain any keys that end in - or _.

All keys MUST consist only of letters, digits, _ or -. All keys MUST start with a letter. The value of the header must be a scalar string. The value string MUST NOT contain characters below ASCII chr(37) except for chr(32) (whitespace).

If the same key name appears multiple times in an array ref, those header lines MUST be sent to the client separately (e.g. multiple Set-Cookie lines).


There MUST be a Content-Type except when the Status is 1xx, 204 or 304, in which case there MUST NOT be a content type.


There MUST NOT be a Content-Length header when the Status is 1xx, 204 or 304.

If the Status is not 1xx, 204 or 304 and there is no Content-Length header, a PSGI server MAY calculate the content length by looking at the Body. This value can then be appended to the list of headers returned by the application.


The response body MUST be returned from the application as either an array reference or a handle.

  • If the body is an array reference, it is expected to contain an array of lines which make up the body.

    my $body = [ "Hello\n", "World\n" ];

    Note that the elements in an array reference are NOT REQUIRED to end in a newline. A server SHOULD write each elements as-is to the client, and SHOULD NOT care if the line ends with newline or not.

    An array reference with a single value is valid. So [ $body ] is a valid response body.

  • The body can instead be a handle, either a Perl built-in filehandle or an IO::Handle-like object.

    open my $body, "</path/to/file";
    open my $body, "<:via(SomePerlIO)", ...;
    my $body = IO::File->new("/path/to/file");
    my $body = SomeClass->new(); # mock class that implements getline() and close()

    Servers SHOULD NOT check the type or class of the body. Instead, they should simply call getline to iterate over the body, and call close when done.

    Servers MAY check if the body is a real filehandle using fileno and Scalar::Util::reftype. If the body is real filehandle, the server MAY optimize using techniques like sendfile(2).

    The body object MAY also respond to a path method. This method is expected to return the path to a file accessible by the server. This allows the server to use this information instead of a file descriptor number to server the file.

    Servers SHOULD set the $/ special variable to the buffer size when reading content from $body using the getline method. This is done by setting $/ with a reference to an integer ($/ = \8192).

    If the body filehandle is a Perl built-in filehandle IO::Handle object, they will respect this value. Similarly, an object which provides the same API MAY also respect this special variable, but are not required to do so.

Delayed Response and Streaming Body

The PSGI interface allows applications and servers to provide a callback-style response instead of the three-element array reference. This allows for a delayed response and a streaming body (server push).

To enable a delayed response, an application SHOULD check if the psgi.streaming environment is true. If it is, the application MAY return a callback as its response.

This callback will be called with another subroutine reference (referred to as the responder from now on) as its only argument. The responder should in turn be called with the standard three element array reference response. This is best illustrated with an example:

my $app = sub {
    my $env = shift;

    # Delays response until it fetches content from the network
    return sub {
        my $responder = shift;

        my $content = fetch_content_from_server();
        $responder->([ 200, $headers, [ $content ] ]);

An application MAY omit the third element (the body) when calling the responder. If the body is omitted, the responder will return yet another an object which implements write, poll_cb and close methods. Again, an example illustrates this best.

my $app = sub {
    my $env = shift;

    # immediately starts the response and stream the content
    return sub {
        my $responder = shift;
        my $writer = $responder->([ 200, [ 'Content-Type', 'application/json' ]]);

        wait_for_events(sub {
            my $new_event = shift;
            if ($new_event) {
                $writer->write($new_event->as_json . "\n");
                # Or:
                # $writer->poll_cb(sub { $_[0]->write($new_event->as_json . "\n") });
            } else {

XXX: still need detalis on write, poll_cb, and close API methods.

This delayed response and streaming API is useful if you want to implement a non-blocking I/O based server streaming or long-poll Comet push technology.

This interface is optional: An application SHOULD check if the server supports streaming before attempting to use it. Servers MAY throw an exception if they do not support streaming a response.

Servers MUST set psgi.streaming to true if this interface is supported, and if it is supported, servers MUST return a writer object when the third argument (response body) to the responder is omitted.


A middleware component takes another PSGI application and runs it. From the perspective of a server, a middleware component is a PSGI application. From the perspective of the application being run by the middleware component, the middleware is the server. Generally, this will be done in order to implement some sort of pre-processing on the PSGI environment hash or post-processing on the response.

Here's a simple example that appends a special HTTP header X-PSGI-Used to any PSGI application.

# $app is a simple PSGI application
my $app = sub {
    my $env = shift;
    return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ];

# $xheader is a piece of middleware that wraps $app
my $xheader = sub {
    my $env = shift;
    my $res = $app->($env);
    push @{$res->[1]}, 'X-PSGI-Used' => 1;
    return $res;

Middleware MUST behave exactly like a PSGI application from the perspective of a server. Middleware MAY decide not to support the streaming interface discussed earlier, but SHOULD pass through the response types that it doesn't understand.


Some parts of this specification are adopted from the following specifications.

I'd like to thank authors of these great documents.


Tatsuhiko Miyagawa <>


The following people have contributed to the PSGI specification and Plack implementation by commiting their code, sending patches, reporting bugs, asking questions, suggesting useful advices, nitpicking, chatting on IRC or commenting on my blog (in no particular order):

Tokuhiro Matsuno
Kazuhiro Osawa
Yuval Kogman
Kazuho Oku
Alexis Sukrieh
Takatoshi Kitano
Stevan Little
Daisuke Murase
Pedro Melo
Jesse Luehrs
John Beppu
Shawn M Moore
Mark Stosberg
Matt S Trout
Jesse Vincent
Chia-liang Kao
Dave Rolsky
Hans Dieter Pearcey
Randy J Ray
Benjamin Trott
Max Maischein
Slaven Rezić
Marcel Grünauer
Masayoshi Sekimura
Brock Wilcox
Piers Cawley
Daisuke Maki
Kang-min Liu
Yasuhiro Matsumoto
Ash Berlin
Artur Bergman
Simon Cozens
Scott McWhirter
Jiro Nishiguchi
Masahiro Chiba
Patrick Donelan
Paul Driver


Copyright Tatsuhiko Miyagawa, 2009.

This document is licensed under the Creative Commons license by-sa.