litestar-app-setup

Use this skill when defining or refactoring the application root object and its global behavior.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "litestar-app-setup" with this command: npx skills add alti3/litestar-skills/alti3-litestar-skills-litestar-app-setup

App Setup

Use this skill when defining or refactoring the application root object and its global behavior.

Execution Workflow

  • Define an importable application entrypoint (app.py , application.py , main.py , or factory) for runtime and CLI discovery.

  • Construct Litestar(...) with explicit route_handlers=[...] (controllers, routers, or handlers); this list is required.

  • Configure app-level concerns intentionally (dependencies, middleware, exception handlers, DTO defaults, request/response classes).

  • Choose lifecycle model:

  • Use on_startup / on_shutdown for straightforward init/teardown hooks.

  • Use lifespan=[...] async context managers for resource lifecycles that require context ownership.

  • Add application hooks (after_exception , before_send , on_app_init ) only for cross-cutting concerns.

  • Use application state sparingly, initialize it explicitly, and inject it intentionally where needed.

  • Validate layered overrides to ensure the closest layer to the handler wins as expected.

Implementation Rules

  • Keep the app module focused on composition, not business logic.

  • Prefer explicit route_handlers=[...] registration and avoid dynamic side effects during import.

  • Keep lifecycle ownership deterministic; avoid mixing competing init/teardown patterns without clear intent.

  • Keep state minimal and stable; avoid mutable global state unless no cleaner scope exists.

  • Use application hooks for instrumentation and cross-cutting behavior, not domain logic.

  • Keep debug=True local-only and tie runtime behavior to environment settings.

Application Object Fundamentals

  • The root of a Litestar service is a Litestar instance.

  • The only required constructor argument is route_handlers , containing controllers/routers/handlers.

  • The application object is the root layer (base path / ) and owns app-wide defaults.

from litestar import Litestar, get

@get("/") async def hello() -> dict[str, str]: return {"hello": "world"}

app = Litestar(route_handlers=[hello])

Startup and Shutdown Hooks

Use on_startup=[...] and on_shutdown=[...] for ordered initialization and teardown:

  • Hooks can be sync or async callables.

  • Startup hooks run on ASGI startup event.

  • Shutdown hooks run on ASGI shutdown event.

  • A common pattern is creating resources in startup and disposing them in shutdown.

from typing import cast

from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine

from litestar import Litestar

DB_URI = "postgresql+asyncpg://postgres:mysecretpassword@pg.db:5432/db"

def get_db_connection(app: Litestar) -> AsyncEngine: if not getattr(app.state, "engine", None): app.state.engine = create_async_engine(DB_URI) return cast("AsyncEngine", app.state.engine)

async def close_db_connection(app: Litestar) -> None: if getattr(app.state, "engine", None): await cast("AsyncEngine", app.state.engine).dispose()

app = Litestar(on_startup=[get_db_connection], on_shutdown=[close_db_connection], route_handlers=[...])

Boundary note:

  • These hooks manage app lifecycle resources.

  • They are not Litestar's event bus. Use litestar-events when emitting decoupled in-process side effects with app.emit(...) and listeners.

Lifespan Context Managers

Use lifespan=[async_context_manager, ...] when resources need a continuous owned context:

from collections.abc import AsyncGenerator from contextlib import asynccontextmanager

from sqlalchemy.ext.asyncio import create_async_engine

from litestar import Litestar

@asynccontextmanager async def db_connection(app: Litestar) -> AsyncGenerator[None, None]: engine = getattr(app.state, "engine", None) if engine is None: engine = create_async_engine("postgresql+asyncpg://postgres:mysecretpassword@pg.db:5432/db") app.state.engine = engine try: yield finally: await engine.dispose()

app = Litestar(route_handlers=[...], lifespan=[db_connection])

Shutdown ordering rule:

  • If multiple lifespan context managers and shutdown hooks are registered, context managers unwind in reverse order before shutdown hooks execute in their declared order.

Application State

Use state for app-scoped shared context, not as a default data transport mechanism.

Key behaviors:

  • App instance is available in ASGI scope as scope["litestar_app"] .

  • You can access app from scope using Litestar.from_scope(scope) .

  • request.app.state and socket.app.state expose state from connection objects.

  • state is also injectable into handlers and dependencies by using a state kwarg.

Initialization options:

  • State({...}) from dict.

  • State(existing_state_or_immutable_state) .

  • State([(key, value), ...]) .

  • State(..., deep_copy=True) to protect against external mutation.

Immutability option:

  • Use ImmutableState typing to enforce no mutation (attribute assignment raises AttributeError ).

from litestar import Litestar, get from litestar.datastructures import State

@get("/") def handler(state: State) -> dict[str, int]: return {"count": state.count}

app = Litestar(route_handlers=[handler], state=State({"count": 100}, deep_copy=True))

Application Hooks

after_exception

  • Called after an exception with (exception, scope) .

  • Intended for side effects such as metrics/logging.

  • Not an exception handler replacement.

before_send

  • Called on each ASGI message with (message, scope) .

  • Gate logic by message["type"] (for example http.response.start ) when mutating headers or metadata.

from litestar import Litestar, get from litestar.datastructures import MutableScopeHeaders

@get("/test") def handler() -> dict[str, str]: return {"key": "value"}

async def before_send_hook_handler(message: dict, scope: dict) -> None: if message["type"] == "http.response.start": headers = MutableScopeHeaders.from_message(message=message) headers["My-Header"] = Litestar.from_scope(scope).state.message

def on_startup(app: Litestar) -> None: app.state.message = "value injected during send"

app = Litestar(route_handlers=[handler], on_startup=[on_startup], before_send=[before_send_hook_handler])

on_app_init

  • Intercepts Litestar constructor arguments before app instantiation.

  • Each hook receives and must return AppConfig .

  • Useful for reusable configuration packages and third-party app configuration systems.

  • on_app_init handlers must be synchronous (cannot be coroutine functions) because they run inside init .

Layered Architecture and Precedence

Litestar layers:

  • Application

  • Router

  • Controller

  • Handler

Precedence rule:

  • For layered parameters, the value set on the layer closest to the handler wins.

Layered parameters documented on the Applications page:

  • after_request

  • after_response

  • before_request

  • cache_control

  • dependencies

  • dto

  • etag

  • exception_handlers

  • guards

  • include_in_schema

  • middleware

  • opt

  • request_class

  • response_class

  • response_cookies

  • response_headers

  • return_dto

  • security

  • tags

  • type_decoders

  • type_encoders

  • websocket_class

Validation Checklist

  • Confirm CLI autodiscovery works (litestar run resolves the correct app).

  • Confirm route_handlers registration is explicit and import-side-effect free.

  • Confirm startup/shutdown hooks run in expected order and release external resources.

  • Confirm lifespan context managers dispose resources and unwind correctly.

  • Confirm mixed lifespan + shutdown sequences match reverse-context + declared-hook ordering.

  • Confirm state initialization uses the intended source and optional deep_copy behavior.

  • Confirm state injection in handlers/dependencies uses the expected state class.

  • Confirm after_exception is used for side effects only, not exception handling.

  • Confirm before_send logic is message-type aware and does not mutate unintended messages.

  • Confirm on_app_init hooks are synchronous and return AppConfig .

  • Confirm layered overrides behave as expected (closest layer wins) for app/router/controller/handler.

Cross-Skill Handoffs

  • Use litestar-routing for endpoint grouping and path design.

  • Use litestar-events for in-process event-bus listeners and app.emit(...) , not startup/shutdown ownership.

  • Use litestar-lifecycle-hooks for request/response interception and cross-cutting instrumentation.

  • Use litestar-dependency-injection for dependency scoping across layers.

  • Use litestar-logging , litestar-middleware , and litestar-openapi for domain-specific configuration depth.

Litestar References

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

litestar-caching

No summary provided by upstream source.

Repository SourceNeeds Review
General

litestar-logging

No summary provided by upstream source.

Repository SourceNeeds Review
General

litestar-requests

No summary provided by upstream source.

Repository SourceNeeds Review
General

litestar-databases

No summary provided by upstream source.

Repository SourceNeeds Review