# How the FastAPI Application Is Mounted with an Optional Frontend in NekoImageGallery

> Discover how the NekoImageGallery codebase conditionally mounts a React frontend alongside the FastAPI application, enabling dual-mode deployment with API routes prefixed by /api.

- Repository: [EdgeNeko/nekoimagegallery](https://github.com/hv0905/nekoimagegallery)
- Tags: internals
- Published: 2026-03-03

---

**The NekoImageGallery server uses the `config.with_frontend` boolean to conditionally prefix all API routes with `/api` and mount a React ASGI application at the root path, enabling seamless dual-mode deployment from a single codebase.**

The `hv0905/nekoimagegallery` repository provides a unified deployment architecture where the same FastAPI backend can run standalone or serve a bundled React frontend. This behavior is controlled by the `with_frontend` configuration flag defined in [`app/config.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/config.py), which triggers dynamic route prefixing and conditional ASGI mounting logic in [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py).

## Configuring the Frontend Toggle

The deployment mode is determined at runtime by the **with_frontend** setting in [`app/config.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/config.py). When set to `True`, the application prepares to serve both the API and the frontend; when `False` (the default), it operates as a pure API server without loading frontend assets.

## Dynamic API Prefix Routing

In [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py) at line 36, the application calculates a dynamic prefix based on the configuration value:

```python
api_prefix = '/api' if config.with_frontend else ''

```

This `api_prefix` variable is injected into the **FastAPI** constructor at lines 36–45, ensuring that OpenAPI documentation and all endpoints shift accordingly:

```python
app = FastAPI(
    lifespan=lifespan,
    title=app.__title__,
    description=app.__description__,
    version=app.__version__,
    openapi_url=f"{api_prefix}/openapi.json",
    docs_url=f"{api_prefix}/docs",
    redoc_url=f"{api_prefix}/redoc",
)

```

When the frontend is enabled, API documentation moves to `/api/docs` and the interactive API explorer is accessible at `/api/redoc`; otherwise, these remain at the root `/docs` and `/redoc` paths.

## Serving Static Files with Prefixed Routes

For local storage backends, static file serving respects the same `api_prefix`. Lines 64–68 of [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py) mount the static directory under the calculated prefix:

```python
if config.storage.method == "local":
    app.mount(
        api_prefix + "/static",
        StaticFiles(directory=pathlib.Path(config.storage.local.path), check_dir=False),
        name="static",
    )

```

This ensures static assets remain accessible under `/static` or `/api/static` depending on the deployment mode, preventing broken image links when the frontend is active.

## Mounting the Optional React Frontend

The optional frontend mounting occurs at lines 92–96 of [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py). When `config.with_frontend` is `True`, the server imports the compiled **React** ASGI application from `neko_image_gallery_app` and mounts it at the root path:

```python
if config.with_frontend:
    from neko_image_gallery_app import asgi_app as frontend_app
    app.mount("/", frontend_app, name="frontend")

```

This makes the React interface available at `http://host:port/` while the API operates under `/api`, preventing route collisions and allowing the frontend to handle client-side routing independently.

## Application Entry Point

The command-line interface in [`main.py`](https://github.com/hv0905/nekoimagegallery/blob/main/main.py) launches the server using **Uvicorn** at line 60:

```python
uvicorn.run("app.webapp:app", host=host, port=port, root_path=root_path)

```

This entry point initializes the configured `app` object from [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py), applying all conditional mounts and prefixes defined above without requiring modifications to the startup command.

## Deployment Modes

The same codebase operates in two distinct modes based on the configuration:

- **API-Only Mode** (`with_frontend=False`): All routes mount at `/`, OpenAPI docs are at `/docs`, and no frontend assets are served.
- **Full-Stack Mode** (`with_frontend=True`): API routes are prefixed with `/api`, docs move to `/api/docs`, and the React app handles requests at `/`.

## Summary

- The `config.with_frontend` flag in [`app/config.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/config.py) controls dual-mode deployment behavior.
- When enabled, `api_prefix` becomes `/api`, shifting all API routes and documentation under `/api` to avoid conflicts with the frontend.
- The React frontend is conditionally mounted at `/` via `app.mount()` only when `with_frontend` is `True`.
- Static files for local storage backends automatically respect the dynamic `api_prefix` to ensure consistent asset delivery.
- The Uvicorn entry point in [`main.py`](https://github.com/hv0905/nekoimagegallery/blob/main/main.py) starts the configured application without requiring code changes between deployment modes.

## Frequently Asked Questions

### How does the API prefix change when the frontend is enabled?

When `config.with_frontend` is set to `True`, the `api_prefix` variable is set to `/api` in [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py), causing all API endpoints, OpenAPI schemas, and automatic documentation to be served under `/api`. In standalone API mode, the prefix is an empty string, placing routes at the root `/`.

### Where is the React frontend mounted when enabled?

The React frontend is mounted at the root path `/` using `app.mount("/", frontend_app, name="frontend")` in [`app/webapp.py`](https://github.com/hv0905/nekoimagegallery/blob/main/app/webapp.py) at lines 92–96. This only occurs when `config.with_frontend` is `True`, allowing the frontend to serve the initial HTML while the API handles requests at `/api`.

### Can I run the API without the frontend?

Yes, by default `with_frontend` is `False`, and the FastAPI application runs as a pure API backend with all routes mounted at the root. No frontend code from `neko_image_gallery_app` is imported or executed in this configuration.

### How are the OpenAPI documentation URLs affected by the frontend setting?

The `docs_url`, `redoc_url`, and `openapi_url` parameters in the **FastAPI** constructor use formatted strings with `api_prefix`. When the frontend is enabled, documentation moves to `/api/docs`, `/api/redoc`, and [`/api/openapi.json`](https://github.com/hv0905/nekoimagegallery/blob/main//api/openapi.json) respectively. In API-only mode, these remain at the standard `/docs`, `/redoc`, and [`/openapi.json`](https://github.com/hv0905/nekoimagegallery/blob/main//openapi.json) paths.