Docs

Configuration

Configure FrameworkBuilder, security defaults, static mounts, external apps, and response behavior.

Open Markdown

FrameworkBuilder turns routes, manifests, static services, external apps, and hardening layers into the Axum router you run in production.

Use this page when you need the complete setup surface in one place. Use Routing, Responses, Static assets, and Deployment for deeper workflow examples.

Minimal Builder

use std::collections::HashMap;

use axum::routing::get;
use proa_framework_axum::{
    router_from_spec, FrameworkBuilder, IslandManifest, ManifestAssets, Route, RouteResponse,
};

async fn home() -> RouteResponse {
    RouteResponse::ssr(HomePage)
}

let manifest = IslandManifest {
    islands: HashMap::new(),
    assets: ManifestAssets::default(),
    import_map: HashMap::new(),
    ssr_bundle: None,
};

let (routes, metadata) = router_from_spec(vec![
    Route::page("/", "Home", get(home)),
]);

let app = FrameworkBuilder::new(manifest)
    .with_dynamic_routes_and_metadata(routes, metadata)
    .build();

with_dynamic_routes_and_metadata is the common path for page routes because it installs both the Axum router and the precomputed metadata map used by response finalization.

Builder Methods

MethodUse it for
FrameworkBuilder::new(manifest)Create the builder with an island manifest and secure defaults.
.with_config(config)Override project paths, codegen flags, and server defaults.
.with_static_service(router)Mount a router under /static.
.with_dynamic_routes(router)Merge an Axum router without a metadata map.
.with_dynamic_routes_and_metadata(router, metadata)Merge Proa route specs plus computed route metadata.
.with_external_app(app)Mount static, SSR, or CSR external applications.
.with_body_limit(bytes)Override the global request body cap.
.with_cross_origin_protection(bool)Toggle browser cross-origin unsafe request protection.
.with_trusted_origin(origin)Add an exact trusted origin such as https://admin.example.com.
.with_security_headers(config)Configure frame policy, HSTS, and CSP.
.with_request_timeout(duration)Override the default request timeout.
.without_request_timeout()Disable the timeout layer. Prefer raising the timeout first.
.with_concurrency_limit(max)Add a global in-flight request cap.
.with_catch_panic(bool)Convert panics into plain 500 responses instead of resetting the connection.
.config()Inspect the current ProaConfig.
.build()Produce the final Axum Router.

Production Defaults

build() applies conservative defaults:

DefaultValue
Body limit1 MiB through Axum DefaultBodyLimit.
Request timeout30s for response production. Streaming bodies keep flowing after the response head is produced.
Cross-origin protectionOn for unsafe browser requests.
Security headersX-Content-Type-Options: nosniff, X-Frame-Options: DENY, and Referrer-Policy: strict-origin-when-cross-origin.
Concurrency limitOff until configured.
Panic catchingOff until configured.

Keep the global body limit small. For uploads, prefer a dedicated nested router with a larger Axum body limit instead of raising the whole app.

Security

Security defaults live on their own pages, because they are policy decisions rather than configuration plumbing:

Builder callCovered in
.with_security_headers(config), .with_strict_csp(), .with_csp_policy(policy)Headers and CSP
.with_trusted_origin(origin)Cross-origin and CSRF

Cross-origin protection, the 1 MiB body limit, and the 30-second request timeout are applied by build() without configuration. See Security for what Proa hardens and what stays yours.

ProaConfig

ProaConfig contains path, codegen, and server defaults:

use proa_framework_axum::{CodegenConfig, PathsConfig, ProaConfig, ServerConfig};

let config = ProaConfig {
    paths: PathsConfig {
        frontend_root: "./apps/web".into(),
        public_dir: "./apps/web/public".into(),
        build_output: "./apps/web/dist".into(),
        ..Default::default()
    },
    codegen: CodegenConfig {
        routes: true,
        components: true,
        islands: true,
        watch: cfg!(debug_assertions),
    },
    server: ServerConfig {
        host: "0.0.0.0".to_string(),
        port: 3000,
        auto_reload: cfg!(debug_assertions),
    },
};

PathsConfig

FieldDefault
crates_root./crates
server_crate./crates/server
frontend_root./apps/web
codegen_output./apps/web/src/.generated
public_dir./apps/web/public
build_output./apps/web/dist

CodegenConfig

FieldDefault
routestrue
componentstrue
islandstrue
watchtrue in debug, false in release

ServerConfig

FieldDefault
port3000
host127.0.0.1
auto_reloadtrue in debug

Static Services

Mount generated assets under /static:

use tower_http::services::ServeDir;

let static_router = axum::Router::new().nest_service("/", ServeDir::new("public"));

let app = FrameworkBuilder::new(manifest)
    .with_static_service(static_router)
    .build();

For public directories, keep untrusted writers out of the served tree. ServeDir rejects .. traversal, but deployments should still treat symlinks and generated files deliberately.

External Apps

Use external app mounts when one path is owned by a different frontend or service:

use proa_framework_axum::ExternalApp;

let app = FrameworkBuilder::new(manifest)
    .with_external_app(ExternalApp::static_app("/docs", "./apps/docs/out"))
    .with_external_app(ExternalApp::ssr_app(
        "/admin",
        "http://127.0.0.1:4000".to_string(),
    ))
    .with_external_app(ExternalApp::csr_app(
        "/console",
        "./apps/console/dist",
        Some("http://127.0.0.1:5173".to_string()),
    ))
    .build();
StrategyConstructorBehavior
StaticExternalApp::static_appServes prebuilt files from disk.
SSRExternalApp::ssr_appReverse proxies to an upstream server.
CSRExternalApp::csr_appServes a built SPA directory; a dev upstream is accepted, but dev proxying is not implemented yet.

SSR proxy mounts strip hop-by-hop headers, rebuild X-Forwarded-* metadata, reuse a shared HTTP client, and buffer bodies with bounded request and response limits.

Proxy Limits

If you build a ProxyConfig directly, defaults are:

SettingDefault
Connect timeout5s
Upstream request timeout30s
Request body cap10 MiB
Upstream response body cap16 MiB

When FrameworkBuilder mounts SSR external apps, it aligns the proxy request cap with the framework body limit.

RouteResponse Quick Reference

ConstructorUse it for
RouteResponse::ssr(component)Sync WebRenderSync pages.
RouteResponse::ssr_async(component)Async pages that do not use a loader.
RouteResponse::ssr_async_with_loader(component, loader)Async pages with a typed loader.
RouteResponse::ssr_stream(component)Streaming pages without a loader.
RouteResponse::ssr_stream_with_loader(component, loader)Streaming pages with a typed loader.

Response modifiers:

ModifierApplies to
.with_islands([...])Sync, async, and streaming SSR responses.
.with_bootstrap(config)SSR responses that need custom React bootstrap behavior.
.with_loader(loader)Async and streaming responses with typed loaders.
.with_render_mode(mode)Async render plans; chunked modes stream, while static and agent modes buffer.

Use Responses for examples and Data loading and streaming for loader and streaming details.

Search

Type at least 2 characters