diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index fedea55..ff3b1c7 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -412,6 +412,11 @@ DEFAULT_INDEX_TABLESPACE = ''
 # Default X-Frame-Options header value
 X_FRAME_OPTIONS = 'SAMEORIGIN'
 
+# The import name of the WSGI application. If this is `None` the default
+# 'django.core.handlers.wsgi.WSGIHandler' is used and instantiated.
+# Otherwise this shall point to an actual WSGI application.
+WSGI_APPLICATION = None
+
 ##############
 # MIDDLEWARE #
 ##############
diff --git a/django/conf/project_template/wsgi.py b/django/conf/project_template/wsgi.py
new file mode 100644
index 0000000..489062d
--- /dev/null
+++ b/django/conf/project_template/wsgi.py
@@ -0,0 +1,27 @@
+"""
+This module contains the actual WSGI application to be used by Django's
+development server and the production environment as the global variable
+named `application`.
+
+This can be used to apply WSGI middlewares::
+
+    from helloworld.wsgi import HelloWorldApplication
+    application = HelloWorldApplication(application)
+
+Of course usually you would have an actual Django WSGI application there,
+but it also might make sense to replace the whole Django WSGI application
+with a custom one that later delegates to the Django one (for instance if
+you want to combine a Django application with an application of another
+framework).
+
+"""
+from django.conf import settings
+
+# You can wrap the application object here to apply WSGI middlewares.
+# The `application` object here is used by both the local runserver
+# command as well as a properly configured WSGI server.
+from django.core.handlers.wsgi import application
+
+# Apply other WSGI middlewares here.
+# from helloworld.wsgi import HelloWorldApplication
+# application = HelloWorldApplication(application)
diff --git a/django/contrib/staticfiles/handlers.py b/django/contrib/staticfiles/handlers.py
index b51b7c8..342ac79 100644
--- a/django/contrib/staticfiles/handlers.py
+++ b/django/contrib/staticfiles/handlers.py
@@ -12,7 +12,9 @@ class StaticFilesHandler(WSGIHandler):
     WSGI middleware that intercepts calls to the static files directory, as
     defined by the STATIC_URL setting, and serves those files.
     """
-    def __init__(self, application, base_dir=None):
+    def __init__(self, application, base_dir=None, enabled=True):
+        # If not enabled this directly proxies to the given application.
+        self.enabled = enabled
         self.application = application
         if base_dir:
             self.base_dir = base_dir
@@ -64,6 +66,6 @@ class StaticFilesHandler(WSGIHandler):
         return super(StaticFilesHandler, self).get_response(request)
 
     def __call__(self, environ, start_response):
-        if not self._should_handle(environ['PATH_INFO']):
-            return self.application(environ, start_response)
-        return super(StaticFilesHandler, self).__call__(environ, start_response)
+        if self.enabled and self._should_handle(environ['PATH_INFO']):
+            return super(StaticFilesHandler, self).__call__(environ, start_response)
+        return self.application(environ, start_response)
diff --git a/django/contrib/staticfiles/management/commands/runserver.py b/django/contrib/staticfiles/management/commands/runserver.py
index c6e56d2..9697736 100644
--- a/django/contrib/staticfiles/management/commands/runserver.py
+++ b/django/contrib/staticfiles/management/commands/runserver.py
@@ -21,7 +21,6 @@ class Command(BaseRunserverCommand):
         handler = super(Command, self).get_handler(*args, **options)
         use_static_handler = options.get('use_static_handler', True)
         insecure_serving = options.get('insecure_serving', False)
-        if (settings.DEBUG and use_static_handler or
-                (use_static_handler and insecure_serving)):
-            handler = StaticFilesHandler(handler)
-        return handler
+        enabled = (settings.DEBUG and use_static_handler or
+                    (use_static_handler and insecure_serving))
+        return StaticFilesHandler(handler, enabled=enabled)
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
index 2acb3b1..b7e429a 100644
--- a/django/core/handlers/wsgi.py
+++ b/django/core/handlers/wsgi.py
@@ -1,4 +1,63 @@
-from pprint import pformat
+"""
+WSGI entrypoints
+
+Overview
+--------
+
+The motivation behind this module is to expose the WSGI application that
+exists in Django to the actual Django user project. The idea is that you
+have a documented way to apply WSGI middlewares that are then being used by
+both the internal WSGI development server as well as any other WSGI server
+in production.
+
+The way it works is that there are a handful of WSGI application objects:
+
+-   django.core.handlers.wsgi.WSGIHandler: this is the implementation of the
+    actual Django WSGI dispatcher and it should be considered an
+    implementation detail. While users are free to subclass and extend it,
+    it's not necessarily supported.
+-   django.core.handlers.wsgi.application: this is the documented WSGI
+    application which is used by default.
+-   django.core.handlers.wsgi.django_application: this is the actual WSGI
+    application that is passed to the servers. It's internally proxying to
+    the configured WSGI application and will most likely be a (decorated)
+    version of the `application`.
+
+The reason why we have multiple applications here is because of the
+ability to apply middlewares.  Basically `application` is the WSGI
+application without any middlewarse applied, `django_application` is a
+proxy to the base application + all applied middlewares.
+
+The middlewares are added according to the WSGI_APPLICATION configuration
+setting which points to a module that imports the `application` as
+`application` and can apply middlewares.
+
+If the WSGI_APPLICATION setting is ``None`` (which is the case for upgraded
+applications from before we had exposed WSGI support) instead of the regular
+application, the `application` is used.
+
+The WSGI_APPLICATION
+--------------------
+
+The WSGI_APPLICATION configuration setting points to an actual WSGI
+application.  By default the project generator will configure that a file
+called `projectname.wsgi` exists and contains a global variable named
+`application`. The contents look like this::
+
+    from django.core.handlers.wsgi import application
+
+This can be used to apply WSGI middlewares::
+
+    from helloworld.wsgi import HelloWorldApplication
+    application = HelloWorldApplication(application)
+
+Of course usually you would have an actual Django WSGI application there, but
+it also might make sense to replace the whole Django WSGI application with
+a custom one that later delegates to the Django one (for instance if you
+want to combine a Django application with an application of another framework).
+
+"""
+from __future__ import with_statement
 import sys
 from threading import Lock
 try:
@@ -6,6 +65,7 @@ try:
 except ImportError:
     from StringIO import StringIO
 import socket
+import warnings
 
 from django import http
 from django.core import signals
@@ -13,6 +73,7 @@ from django.core.handlers import base
 from django.core.urlresolvers import set_script_prefix
 from django.utils import datastructures
 from django.utils.encoding import force_unicode, iri_to_uri
+from django.utils.importlib import import_module
 from django.utils.log import getLogger
 
 logger = getLogger('django.request')
@@ -212,8 +273,6 @@ class WSGIHandler(base.BaseHandler):
     request_class = WSGIRequest
 
     def __call__(self, environ, start_response):
-        from django.conf import settings
-
         # Set up middleware if needed. We couldn't do this earlier, because
         # settings weren't available.
         if self._request_middleware is None:
@@ -259,3 +318,38 @@ class WSGIHandler(base.BaseHandler):
         start_response(status, response_headers)
         return response
 
+# the base WSGI application
+application = WSGIHandler()
+
+
+class DjangoWSGIApplication(object):
+    """
+    Implements a proxy to the actual WSGI application as configured
+    by the user in settings.WSGI_APPLICATION which will usually be the
+    `application`, optionally with middlewares applied.
+    """
+
+    def __init__(self):
+        self._instance = None
+        self._instance_lock = Lock()
+
+    def __call__(self, environ, start_response):
+        if self._instance is not None:
+            application = self._instance
+        else:
+            with self._instance_lock:
+                if self._instance is not None:
+                    return self._instance
+                from django.conf import settings
+                if settings.WSGI_APPLICATION is None:
+                    warnings.warn(
+                        "The WSGI_APPLICATION setting has to be specified "
+                        "to run Django.", PendingDeprecationWarning)
+                else:
+                    module_name, attr = settings.WSGI_APPLICATION.rsplit('.', 1)
+                    application = getattr(import_module(module_name), attr)
+                self._instance = application
+        return application(environ, start_response)
+
+
+django_application = DjangoWSGIApplication()
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index 2e693e7..c84bf30 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -5,7 +5,7 @@ import sys
 import socket
 
 from django.core.management.base import BaseCommand, CommandError
-from django.core.handlers.wsgi import WSGIHandler
+from django.core.handlers.wsgi import django_application
 from django.core.servers.basehttp import AdminMediaHandler, run, WSGIServerException
 from django.utils import autoreload
 
@@ -37,7 +37,7 @@ class BaseRunserverCommand(BaseCommand):
         """
         Returns the default WSGI handler for the runner.
         """
-        return WSGIHandler()
+        return django_application
 
     def handle(self, addrport='', *args, **options):
         self.use_ipv6 = options.get('use_ipv6')
diff --git a/django/core/servers/fastcgi.py b/django/core/servers/fastcgi.py
index 7e724c2..75ef364 100644
--- a/django/core/servers/fastcgi.py
+++ b/django/core/servers/fastcgi.py
@@ -138,7 +138,7 @@ def runfastcgi(argset=[], **kwargs):
         return False
 
     # Prep up and go
-    from django.core.handlers.wsgi import WSGIHandler
+    from django.core.handlers.wsgi import django_application
 
     if options["host"] and options["port"] and not options["socket"]:
         wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
@@ -177,7 +177,7 @@ def runfastcgi(argset=[], **kwargs):
         fp.write("%d\n" % os.getpid())
         fp.close()
 
-    WSGIServer(WSGIHandler(), **wsgi_opts).run()
+    WSGIServer(django_application, **wsgi_opts).run()
 
 if __name__ == '__main__':
     runfastcgi(sys.argv[1:])
