diff --git a/CHANGES.md b/CHANGES.md
index fc690ee50..4aaef9511 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,10 @@
 # Changes
 
-## [1.0.0-alpha.3] - 2019-04-xx
+## [1.0.0-alpha.4] - 2019-04-xx
+
+### Added
+
+* `App::configure()` allow to offload app configuration to different methods
 
 ### Changed
 
diff --git a/actix-multipart/README.md b/actix-multipart/README.md
index 2a65840a1..2739ff3d5 100644
--- a/actix-multipart/README.md
+++ b/actix-multipart/README.md
@@ -1 +1 @@
-# Multipart support for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-session)](https://crates.io/crates/actix-session) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# Multipart support for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-multipart)](https://crates.io/crates/actix-multipart) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
diff --git a/src/app.rs b/src/app.rs
index fd91d0728..802569458 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -15,7 +15,7 @@ use bytes::Bytes;
 use futures::{IntoFuture, Stream};
 
 use crate::app_service::{AppChain, AppEntry, AppInit, AppRouting, AppRoutingFactory};
-use crate::config::{AppConfig, AppConfigInner};
+use crate::config::{AppConfig, AppConfigInner, RouterConfig};
 use crate::data::{Data, DataFactory};
 use crate::dev::{Payload, PayloadStream, ResourceDef};
 use crate::error::{Error, PayloadError};
@@ -257,6 +257,55 @@ where
         }
     }
 
+    /// Run external configuration as part of the application building
+    /// process
+    ///
+    /// This function is useful for moving parts of configuration to a
+    /// different module or even library. For example,
+    /// some of the resource's configuration could be moved to different module.
+    ///
+    /// ```rust
+    /// # extern crate actix_web;
+    /// use actix_web::{web, middleware, App, HttpResponse};
+    ///
+    /// // this function could be located in different module
+    /// fn config<P>(cfg: &mut web::RouterConfig<P>) {
+    ///     cfg.service(web::resource("/test")
+    ///         .route(web::get().to(|| HttpResponse::Ok()))
+    ///         .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
+    ///     );
+    /// }
+    ///
+    /// fn main() {
+    ///     let app = App::new()
+    ///         .wrap(middleware::Logger::default())
+    ///         .configure(config)  // <- register resources
+    ///         .route("/index.html", web::get().to(|| HttpResponse::Ok()));
+    /// }
+    /// ```
+    pub fn configure<F>(mut self, f: F) -> AppRouter<T, Out, Body, AppEntry<Out>>
+    where
+        F: Fn(&mut RouterConfig<Out>),
+    {
+        let mut cfg = RouterConfig::new();
+        f(&mut cfg);
+        self.data.extend(cfg.data);
+
+        let fref = Rc::new(RefCell::new(None));
+
+        AppRouter {
+            chain: self.chain,
+            default: None,
+            endpoint: AppEntry::new(fref.clone()),
+            factory_ref: fref,
+            data: self.data,
+            config: self.config,
+            services: cfg.services,
+            external: cfg.external,
+            _t: PhantomData,
+        }
+    }
+
     /// Configure route for a specific path.
     ///
     /// This is a simplified version of the `App::service()` method.
@@ -382,6 +431,45 @@ where
         InitError = (),
     >,
 {
+    /// Run external configuration as part of the application building
+    /// process
+    ///
+    /// This function is useful for moving parts of configuration to a
+    /// different module or even library. For example,
+    /// some of the resource's configuration could be moved to different module.
+    ///
+    /// ```rust
+    /// # extern crate actix_web;
+    /// use actix_web::{web, middleware, App, HttpResponse};
+    ///
+    /// // this function could be located in different module
+    /// fn config<P>(cfg: &mut web::RouterConfig<P>) {
+    ///     cfg.service(web::resource("/test")
+    ///         .route(web::get().to(|| HttpResponse::Ok()))
+    ///         .route(web::head().to(|| HttpResponse::MethodNotAllowed()))
+    ///     );
+    /// }
+    ///
+    /// fn main() {
+    ///     let app = App::new()
+    ///         .wrap(middleware::Logger::default())
+    ///         .configure(config)  // <- register resources
+    ///         .route("/index.html", web::get().to(|| HttpResponse::Ok()));
+    /// }
+    /// ```
+    pub fn configure<F>(mut self, f: F) -> Self
+    where
+        F: Fn(&mut RouterConfig<P>),
+    {
+        let mut cfg = RouterConfig::new();
+        f(&mut cfg);
+        self.data.extend(cfg.data);
+        self.services.extend(cfg.services);
+        self.external.extend(cfg.external);
+
+        self
+    }
+
     /// Configure route for a specific path.
     ///
     /// This is a simplified version of the `App::service()` method.
diff --git a/src/config.rs b/src/config.rs
index ceb58feb7..1e552291f 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -5,11 +5,18 @@ use std::rc::Rc;
 use actix_http::Extensions;
 use actix_router::ResourceDef;
 use actix_service::{boxed, IntoNewService, NewService};
+use futures::IntoFuture;
 
+use crate::data::{Data, DataFactory};
 use crate::error::Error;
 use crate::guard::Guard;
+use crate::resource::Resource;
 use crate::rmap::ResourceMap;
-use crate::service::{ServiceRequest, ServiceResponse};
+use crate::route::Route;
+use crate::service::{
+    HttpServiceFactory, ServiceFactory, ServiceFactoryWrapper, ServiceRequest,
+    ServiceResponse,
+};
 
 type Guards = Vec<Box<Guard>>;
 type HttpNewService<P> =
@@ -157,3 +164,140 @@ impl Default for AppConfigInner {
         }
     }
 }
+
+/// Router config. It is used for external configuration.
+/// Part of application configuration could be offloaded
+/// to set of external methods. This could help with
+/// modularization of big application configuration.
+pub struct RouterConfig<P: 'static> {
+    pub(crate) services: Vec<Box<ServiceFactory<P>>>,
+    pub(crate) data: Vec<Box<DataFactory>>,
+    pub(crate) external: Vec<ResourceDef>,
+}
+
+impl<P: 'static> RouterConfig<P> {
+    pub(crate) fn new() -> Self {
+        Self {
+            services: Vec::new(),
+            data: Vec::new(),
+            external: Vec::new(),
+        }
+    }
+
+    /// Set application data. Applicatin data could be accessed
+    /// by using `Data<T>` extractor where `T` is data type.
+    ///
+    /// This is same as `App::data()` method.
+    pub fn data<S: 'static>(&mut self, data: S) -> &mut Self {
+        self.data.push(Box::new(Data::new(data)));
+        self
+    }
+
+    /// Set application data factory. This function is
+    /// similar to `.data()` but it accepts data factory. Data object get
+    /// constructed asynchronously during application initialization.
+    ///
+    /// This is same as `App::data_dactory()` method.
+    pub fn data_factory<F, R>(&mut self, data: F) -> &mut Self
+    where
+        F: Fn() -> R + 'static,
+        R: IntoFuture + 'static,
+        R::Error: std::fmt::Debug,
+    {
+        self.data.push(Box::new(data));
+        self
+    }
+
+    /// Configure route for a specific path.
+    ///
+    /// This is same as `App::route()` method.
+    pub fn route(&mut self, path: &str, mut route: Route<P>) -> &mut Self {
+        self.service(
+            Resource::new(path)
+                .add_guards(route.take_guards())
+                .route(route),
+        )
+    }
+
+    /// Register http service.
+    ///
+    /// This is same as `App::service()` method.
+    pub fn service<F>(&mut self, factory: F) -> &mut Self
+    where
+        F: HttpServiceFactory<P> + 'static,
+    {
+        self.services
+            .push(Box::new(ServiceFactoryWrapper::new(factory)));
+        self
+    }
+
+    /// Register an external resource.
+    ///
+    /// External resources are useful for URL generation purposes only
+    /// and are never considered for matching at request time. Calls to
+    /// `HttpRequest::url_for()` will work as expected.
+    ///
+    /// This is same as `App::external_service()` method.
+    pub fn external_resource<N, U>(&mut self, name: N, url: U) -> &mut Self
+    where
+        N: AsRef<str>,
+        U: AsRef<str>,
+    {
+        let mut rdef = ResourceDef::new(url.as_ref());
+        *rdef.name_mut() = name.as_ref().to_string();
+        self.external.push(rdef);
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use actix_service::Service;
+
+    use super::*;
+    use crate::http::StatusCode;
+    use crate::test::{block_on, init_service, TestRequest};
+    use crate::{web, App, HttpResponse};
+
+    #[test]
+    fn test_data() {
+        let cfg = |cfg: &mut RouterConfig<_>| {
+            cfg.data(10usize);
+        };
+
+        let mut srv =
+            init_service(App::new().configure(cfg).service(
+                web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
+            ));
+        let req = TestRequest::default().to_request();
+        let resp = block_on(srv.call(req)).unwrap();
+        assert_eq!(resp.status(), StatusCode::OK);
+    }
+
+    #[test]
+    fn test_data_factory() {
+        let cfg = |cfg: &mut RouterConfig<_>| {
+            cfg.data_factory(|| Ok::<_, ()>(10usize));
+        };
+
+        let mut srv =
+            init_service(App::new().configure(cfg).service(
+                web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
+            ));
+        let req = TestRequest::default().to_request();
+        let resp = block_on(srv.call(req)).unwrap();
+        assert_eq!(resp.status(), StatusCode::OK);
+
+        let cfg2 = |cfg: &mut RouterConfig<_>| {
+            cfg.data_factory(|| Ok::<_, ()>(10u32));
+        };
+        let mut srv = init_service(
+            App::new()
+                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()))
+                .configure(cfg2),
+        );
+        let req = TestRequest::default().to_request();
+        let resp = block_on(srv.call(req)).unwrap();
+        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
+    }
+}
diff --git a/src/web.rs b/src/web.rs
index 65b3cfc70..94c98c22a 100644
--- a/src/web.rs
+++ b/src/web.rs
@@ -13,6 +13,7 @@ use crate::responder::Responder;
 use crate::route::Route;
 use crate::scope::Scope;
 
+pub use crate::config::RouterConfig;
 pub use crate::data::{Data, RouteData};
 pub use crate::request::HttpRequest;
 pub use crate::types::*;