diff --git a/src/httpserver/CMakeLists.txt b/src/httpserver/CMakeLists.txt
index efcce0d..a552ca2 100644
--- a/src/httpserver/CMakeLists.txt
+++ b/src/httpserver/CMakeLists.txt
@@ -47,3 +47,10 @@ qt_extend_target(HttpServer CONDITION QT_FEATURE_ssl
     PUBLIC_LIBRARIES
         Qt::SslServer
 )
+
+qt_extend_target(HttpServer CONDITION TARGET Qt::Concurrent
+    SOURCES
+        qhttpserverfutureresponse.cpp qhttpserverfutureresponse.h
+    PUBLIC_LIBRARIES
+        Qt::Concurrent
+)
diff --git a/src/httpserver/httpserver.pro b/src/httpserver/httpserver.pro
index fd1a231..9e9d17a 100644
--- a/src/httpserver/httpserver.pro
+++ b/src/httpserver/httpserver.pro
@@ -37,6 +37,12 @@ SOURCES += \
     qhttpserverrouter.cpp \
     qhttpserverrouterrule.cpp
 
+qtHaveModule(concurrent) {
+    QT += concurrent
+    HEADERS += qhttpserverfutureresponse.h
+    SOURCES += qhttpserverfutureresponse.cpp
+}
+
 include(../3rdparty/http-parser.pri)
 
 load(qt_module)
diff --git a/src/httpserver/qhttpserver.h b/src/httpserver/qhttpserver.h
index 97c5bc5..5274d0f 100644
--- a/src/httpserver/qhttpserver.h
+++ b/src/httpserver/qhttpserver.h
@@ -59,6 +59,15 @@ class Q_HTTPSERVER_EXPORT QHttpServer final : public QAbstractHttpServer
         using Type = typename VariadicTypeAt<sizeof ... (Ts) - 1, Ts...>::Type;
     };
 
+
+    template<typename T>
+    using ResponseType =
+        typename std::conditional<
+            std::is_base_of<QHttpServerResponse, T>::value,
+            T,
+            QHttpServerResponse
+        >::type;
+
 public:
     explicit QHttpServer(QObject *parent = nullptr);
     ~QHttpServer();
@@ -160,7 +169,16 @@ private:
                          const QHttpServerRequest &request,
                          QTcpSocket *socket)
     {
-        QHttpServerResponse response(boundViewHandler());
+        ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler());
+        sendResponse(std::move(response), request, socket);
+    }
+
+    template<typename ViewTraits, typename T>
+    typename std::enable_if<ViewTraits::Arguments::Last::IsRequest::Value &&
+                            ViewTraits::Arguments::PlaceholdersCount == 1, void>::type
+            responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket)
+    {
+        ResponseType<typename ViewTraits::ReturnType> response(boundViewHandler(request));
         sendResponse(std::move(response), request, socket);
     }
 
@@ -172,15 +190,6 @@ private:
         boundViewHandler(makeResponder(request, socket), request);
     }
 
-    template<typename ViewTraits, typename T>
-    typename std::enable_if<ViewTraits::Arguments::Last::IsRequest::Value &&
-                            ViewTraits::Arguments::PlaceholdersCount == 1, void>::type
-            responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket)
-    {
-        QHttpServerResponse response(boundViewHandler(request));
-        sendResponse(std::move(response), request, socket);
-    }
-
     template<typename ViewTraits, typename T>
     typename std::enable_if<ViewTraits::Arguments::Last::IsResponder::Value &&
                             ViewTraits::Arguments::PlaceholdersCount == 2, void>::type
diff --git a/src/httpserver/qhttpserverfutureresponse.cpp b/src/httpserver/qhttpserverfutureresponse.cpp
new file mode 100644
index 0000000..3d2784b
--- /dev/null
+++ b/src/httpserver/qhttpserverfutureresponse.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhttpserverfutureresponse.h"
+
+#include <QtCore/qfuture.h>
+#include <QtCore/qfuturewatcher.h>
+
+#include <QtNetwork/qtcpsocket.h>
+
+#include <QtHttpServer/qhttpserverresponder.h>
+
+#include <private/qhttpserverresponse_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QHttpServerFutureResponse
+    \brief QHttpServerFutureResponse is a simplified API for asynchronous responses.
+
+    \code
+
+    QHttpServer server;
+
+    server.route("/feature/", [] (int id) -> QHttpServerFutureResponse {
+        auto future = QtConcurrent::run([] () {
+            return QHttpServerResponse("the future is coming");
+        });
+
+        return future;
+    });
+    server.listen();
+
+    \endcode
+*/
+
+struct QResponseWatcher : public QFutureWatcher<QHttpServerResponse>
+{
+    Q_OBJECT
+
+public:
+    QResponseWatcher(QHttpServerResponder &&_responder)
+        : QFutureWatcher<QHttpServerResponse>(),
+          responder(std::move(_responder)) {
+    }
+
+    QHttpServerResponder responder;
+};
+
+class QHttpServerFutureResponsePrivate : public QHttpServerResponsePrivate
+{
+public:
+    QHttpServerFutureResponsePrivate(const QFuture<QHttpServerResponse> &futureResponse)
+        : QHttpServerResponsePrivate(),
+          futureResp(futureResponse)
+    {
+    }
+
+    QFuture<QHttpServerResponse> futureResp;
+};
+
+/*!
+    Constructs a new QHttpServerFutureResponse with the \a future response.
+*/
+QHttpServerFutureResponse::QHttpServerFutureResponse(const QFuture<QHttpServerResponse> &futureResp)
+    : QHttpServerFutureResponse(new QHttpServerFutureResponsePrivate{futureResp})
+{
+}
+
+/*!
+    \internal
+*/
+QHttpServerFutureResponse::QHttpServerFutureResponse(QHttpServerFutureResponsePrivate *d)
+    : QHttpServerResponse(d)
+{
+}
+
+/*!
+    \reimp
+*/
+void QHttpServerFutureResponse::write(QHttpServerResponder &&responder) const
+{
+    if (!d_ptr->derived) {
+        QHttpServerResponse::write(std::move(responder));
+        return;
+    }
+
+    Q_D(const QHttpServerFutureResponse);
+
+    auto socket = responder.socket();
+    auto futureWatcher = new QResponseWatcher(std::move(responder));
+
+    QObject::connect(socket, &QObject::destroyed,
+                     futureWatcher, &QObject::deleteLater);
+    QObject::connect(futureWatcher, &QFutureWatcherBase::finished,
+                     socket,
+                    [futureWatcher] () mutable {
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+        auto resp = futureWatcher->future().d.takeResult();
+#else
+        auto resp = futureWatcher->future().takeResult();
+#endif
+        resp.write(std::move(futureWatcher->responder));
+        futureWatcher->deleteLater();
+    });
+
+    futureWatcher->setFuture(d->futureResp);
+}
+
+QT_END_NAMESPACE
+
+#include "qhttpserverfutureresponse.moc"
diff --git a/src/httpserver/qhttpserverfutureresponse.h b/src/httpserver/qhttpserverfutureresponse.h
new file mode 100644
index 0000000..45dc376
--- /dev/null
+++ b/src/httpserver/qhttpserverfutureresponse.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Mikhail Svetkin <mikhail.svetkin@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHTTPSERVERFUTURERESPONSE_H
+#define QHTTPSERVERFUTURERESPONSE_H
+
+#include <QtHttpServer/qhttpserverresponse.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qfuture.h>
+
+#include <QtConcurrent>
+
+#include <mutex>
+
+QT_BEGIN_NAMESPACE
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+
+template <>
+class QFutureInterface<QHttpServerResponse> : public QFutureInterfaceBase
+{
+public:
+    QFutureInterface(State initialState = NoState)
+        : QFutureInterfaceBase(initialState)
+    {
+        refT();
+    }
+    QFutureInterface(const QFutureInterface &other)
+        : QFutureInterfaceBase(other)
+    {
+        refT();
+    }
+    ~QFutureInterface()
+    {
+        if (!derefT())
+            resultStoreBase().template clear<QHttpServerResponse>();
+    }
+
+    static QFutureInterface canceledResult()
+    { return QFutureInterface(State(Started | Finished | Canceled)); }
+
+    QFutureInterface &operator=(const QFutureInterface &other)
+    {
+        other.refT();
+        if (!derefT())
+            resultStoreBase().template clear<QHttpServerResponse>();
+        QFutureInterfaceBase::operator=(other);
+        return *this;
+    }
+
+    inline QFuture<QHttpServerResponse> future()
+    {
+        return QFuture<QHttpServerResponse>(this);
+    }
+
+    void reportAndMoveResult(QHttpServerResponse &&result, int index = -1)
+    {
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+        std::lock_guard<QMutex> locker{*mutex()};
+#else
+        std::lock_guard<QMutex> locker{mutex(0)};
+#endif
+        if (queryState(Canceled) || queryState(Finished))
+            return;
+
+        QtPrivate::ResultStoreBase &store = resultStoreBase();
+
+        const int oldResultCount = store.count();
+        const int insertIndex = store.addResult(
+                index, static_cast<void *>(new QHttpServerResponse(std::move_if_noexcept(result))));
+        if (!store.filterMode() || oldResultCount < store.count()) // Let's make sure it's not in pending results.
+            reportResultsReady(insertIndex, store.count());
+    }
+
+    void reportFinished()
+    {
+        QFutureInterfaceBase::reportFinished();
+    }
+
+    QHttpServerResponse takeResult()
+    {
+        if (isCanceled()) {
+            exceptionStore().throwPossibleException();
+            return QHttpServerResponse::StatusCode::NotFound;
+        }
+
+        // Note: we wait for all, this is intentional,
+        // not to mess with other unready results.
+        waitForResult(-1);
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+        std::lock_guard<QMutex> locker{*mutex()};
+#else
+        std::lock_guard<QMutex> locker{mutex(0)};
+#endif
+        QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
+        auto ret = std::move_if_noexcept(
+            *const_cast<QHttpServerResponse *>(position.pointer<QHttpServerResponse>()));
+        resultStoreBase().template clear<QHttpServerResponse>();
+
+        return ret;
+    }
+};
+
+#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+
+namespace QtConcurrent {
+
+template <>
+class RunFunctionTask<QHttpServerResponse> : public RunFunctionTaskBase<QHttpServerResponse>
+{
+public:
+    void run() override
+    {
+        if (this->isCanceled()) {
+            this->reportFinished();
+            return;
+        }
+#ifndef QT_NO_EXCEPTIONS
+        try {
+#endif
+            this->runFunctor();
+#ifndef QT_NO_EXCEPTIONS
+        } catch (QException &e) {
+            QFutureInterface<QHttpServerResponse>::reportException(e);
+        } catch (...) {
+            QFutureInterface<QHttpServerResponse>::reportException(QUnhandledException());
+        }
+#endif
+        this->reportAndMoveResult(std::move_if_noexcept(result));
+        this->reportFinished();
+    }
+
+    QHttpServerResponse result{QHttpServerResponse::StatusCode::NotFound};
+};
+
+}
+
+class QHttpServerFutureResponsePrivate;
+class Q_HTTPSERVER_EXPORT QHttpServerFutureResponse : public QHttpServerResponse
+{
+    Q_DECLARE_PRIVATE(QHttpServerFutureResponse)
+
+public:
+    using QHttpServerResponse::QHttpServerResponse;
+
+    QHttpServerFutureResponse(const QFuture<QHttpServerResponse> &futureResponse);
+
+    virtual void write(QHttpServerResponder &&responder) const override;
+
+protected:
+    QHttpServerFutureResponse(QHttpServerFutureResponsePrivate *d);
+};
+
+QT_END_NAMESPACE
+
+#endif // QHTTPSERVERFUTURERESPONSE_H
diff --git a/src/httpserver/qhttpserverresponse.cpp b/src/httpserver/qhttpserverresponse.cpp
index 5bd510b..47c3b49 100644
--- a/src/httpserver/qhttpserverresponse.cpp
+++ b/src/httpserver/qhttpserverresponse.cpp
@@ -41,6 +41,16 @@
 
 QT_BEGIN_NAMESPACE
 
+QHttpServerResponsePrivate::QHttpServerResponsePrivate(
+        QByteArray &&d, const QHttpServerResponse::StatusCode sc)
+    : data(std::move(d)),
+      statusCode(sc)
+{ }
+
+QHttpServerResponsePrivate::QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc)
+    : statusCode(sc)
+{ }
+
 QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept
     : d_ptr(other.d_ptr.take())
 {
@@ -100,35 +110,33 @@ QHttpServerResponse::QHttpServerResponse(const QJsonArray &data)
 QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
                                          const QByteArray &data,
                                          const StatusCode status)
-    : QHttpServerResponse(mimeType,
-                          new QHttpServerResponsePrivate{data, status, {}})
+    : d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status))
 {
+    setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
 }
 
 QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
                                          const QByteArray &data,
                                          const StatusCode status)
-    : QHttpServerResponse(std::move(mimeType),
-                          new QHttpServerResponsePrivate{data, status, {}})
+    : d_ptr(new QHttpServerResponsePrivate(QByteArray(data), status))
 {
+    setHeader(QHttpServerLiterals::contentTypeHeader(), std::move(mimeType));
 }
 
 QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
                                          QByteArray &&data,
                                          const StatusCode status)
-    : QHttpServerResponse(
-            mimeType,
-            new QHttpServerResponsePrivate{std::move(data), status, {}})
+    : d_ptr(new QHttpServerResponsePrivate(std::move(data), status))
 {
+    setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
 }
 
 QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
                                          QByteArray &&data,
                                          const StatusCode status)
-    : QHttpServerResponse(
-            std::move(mimeType),
-            new QHttpServerResponsePrivate{std::move(data), status, {}})
+    : d_ptr(new QHttpServerResponsePrivate(std::move(data), status))
 {
+    setHeader(QHttpServerLiterals::contentTypeHeader(), std::move(mimeType));
 }
 
 QHttpServerResponse::~QHttpServerResponse()
@@ -146,19 +154,10 @@ QHttpServerResponse QHttpServerResponse::fromFile(const QString &fileName)
     return QHttpServerResponse(mimeType, data);
 }
 
-QHttpServerResponse::QHttpServerResponse(const QByteArray &mimeType,
-                                         QHttpServerResponsePrivate *d)
+QHttpServerResponse::QHttpServerResponse(QHttpServerResponsePrivate *d)
     : d_ptr(d)
 {
-    setHeader(QHttpServerLiterals::contentTypeHeader(), mimeType);
-}
-
-QHttpServerResponse::QHttpServerResponse(QByteArray &&mimeType,
-                                         QHttpServerResponsePrivate *d)
-    : d_ptr(d)
-{
-    setHeader(QHttpServerLiterals::contentTypeHeader(),
-              std::move(mimeType));
+    d->derived = true;
 }
 
 /*!
diff --git a/src/httpserver/qhttpserverresponse.h b/src/httpserver/qhttpserverresponse.h
index df748cb..6d2bc1d 100644
--- a/src/httpserver/qhttpserverresponse.h
+++ b/src/httpserver/qhttpserverresponse.h
@@ -118,12 +118,8 @@ public:
 
     virtual void write(QHttpServerResponder &&responder) const;
 
-private:
-    QHttpServerResponse(const QByteArray &mimeType,
-                        QHttpServerResponsePrivate *d);
-
-    QHttpServerResponse(QByteArray &&mimeType,
-                        QHttpServerResponsePrivate *d);
+protected:
+    QHttpServerResponse(QHttpServerResponsePrivate *d);
 
     QScopedPointer<QHttpServerResponsePrivate> d_ptr;
 };
diff --git a/src/httpserver/qhttpserverresponse_p.h b/src/httpserver/qhttpserverresponse_p.h
index 8b81ad0..5011552 100644
--- a/src/httpserver/qhttpserverresponse_p.h
+++ b/src/httpserver/qhttpserverresponse_p.h
@@ -59,10 +59,16 @@ class QHttpServerResponsePrivate
     };
 
 public:
+    explicit QHttpServerResponsePrivate() = default;
+    virtual ~QHttpServerResponsePrivate() = default;
+
+    QHttpServerResponsePrivate(QByteArray &&d, const QHttpServerResponse::StatusCode sc);
+    QHttpServerResponsePrivate(const QHttpServerResponse::StatusCode sc);
+
     QByteArray data;
     QHttpServerResponse::StatusCode statusCode;
-
     std::unordered_multimap<QByteArray, QByteArray, HashHelper> headers;
+    bool derived{false};
 };
 
 QT_END_NAMESPACE
diff --git a/src/httpserver/qhttpserverrouterviewtraits.h b/src/httpserver/qhttpserverrouterviewtraits.h
index 2e812a5..b572675 100644
--- a/src/httpserver/qhttpserverrouterviewtraits.h
+++ b/src/httpserver/qhttpserverrouterviewtraits.h
@@ -151,6 +151,7 @@ template <typename ViewHandler, bool DisableStaticAssert = false>
 struct QHttpServerRouterViewTraits
 {
     using Helpers = typename QtPrivate::RouterViewTraitsHelper<ViewHandler, DisableStaticAssert>;
+    using ReturnType = typename Helpers::FunctionTraits::ReturnType;
     using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{}));
     using BindableType = decltype(
             Helpers::template BindType<Arguments::CapturableCount>::eval(
diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp
index c7176ff..cf5c43d 100644
--- a/tests/auto/qhttpserver/tst_qhttpserver.cpp
+++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp
@@ -31,6 +31,10 @@
 #include <QtHttpServer/qhttpserverrequest.h>
 #include <QtHttpServer/qhttpserverrouterrule.h>
 
+#if QT_CONFIG(concurrent)
+#  include <QtHttpServer/qhttpserverfutureresponse.h>
+#endif
+
 #include <private/qhttpserverrouterrule_p.h>
 #include <private/qhttpserverliterals_p.h>
 
@@ -296,6 +300,20 @@ void tst_QHttpServer::initTestCase()
         return std::move(resp);
     });
 
+#if QT_CONFIG(concurrent)
+    httpserver.route("/future/", [] (int id) -> QHttpServerFutureResponse {
+        if (id == 0)
+            return QHttpServerResponse::StatusCode::NotFound;
+
+        auto future = QtConcurrent::run([] () {
+            QTest::qSleep(500);
+            return QHttpServerResponse("future is coming");
+        });
+
+        return future;
+    });
+#endif
+
     quint16 port = httpserver.listen();
     if (!port)
         qCritical() << "Http server listen failed";
@@ -526,6 +544,20 @@ void tst_QHttpServer::routeGet_data()
         << "text/plain"
         << "part 1 of the message, part 2 of the message";
 
+#if QT_CONFIG(concurrent)
+    QTest::addRow("future")
+        << urlBase.arg("/future/1")
+        << 200
+        << "text/plain"
+        << "future is coming";
+
+    QTest::addRow("future-not-found")
+        << urlBase.arg("/future/0")
+        << 404
+        << "application/x-empty"
+        << "";
+#endif
+
 #if QT_CONFIG(ssl)
 
     QTest::addRow("hello world, ssl")