Skip to main content

XIME Framework

One DI container for devices, services and people.

PyPI version Python License: MIT

English | Tiếng Việt

Documentation · Examples


XIME is a convention layer for Python microservices. It sits on top of FastAPI, SQLAlchemy and gRPC - providing automatic dependency injection, startup-time graph validation, and architectural guardrails so you can focus on business logic instead of wiring.

Seven ways in: HTTP, WebSocket, gRPC, Unix sockets, MQTT, Modbus TCP and OPC UA - one application, one dependency graph, one lifecycle. Talking to a PLC and serving a browser are the same kind of work here.

And it scales without a process manager in front of it. Since 0.8, share_load() plus a count: in the config makes the processes share one listening socket - no gunicorn, no supervisor, no nginx balancing between ports. Measured 2026-08-25: 1.97x throughput on two processes, 3.75x on four.

# Before XIME - wire everything manually
container.user_service = providers.Singleton(
    UserService,
    repository=container.user_repository,
    transaction=container.transaction_manager,
)

# With XIME - just write your class
class UserService:
    def __init__(
        self,
        repository: UserRepository,
        transaction: TransactionManager,
    ):
        self.repository = repository
        self.transaction = transaction

XIME reads your type hints, scans your packages, builds the dependency graph, validates it at startup, and wires everything together - automatically.


Why XIME?

Python has excellent libraries for HTTP, databases, and serialization. What it lacks is a convention layer that:

  • Automatically discovers and wires dependencies from constructor type hints
  • Enforces architectural boundaries through directory structure
  • Validates the dependency graph at startup - not at runtime when a user hits an endpoint
  • Provides a consistent structure for Clean Architecture / DDD / Modular Monolith projects

XIME fills that gap. It does not replace FastAPI or SQLAlchemy - it makes them easier to use at scale.

What it borrows from Spring Boot, and what it deliberately drops

The debt is real and worth naming: starters, and failing at startup rather than in production. Ask for a dependency nothing can supply and the process refuses to boot, with the class and parameter named.

What XIME drops is just as deliberate, because these are the parts that do not survive the trip into Python:

Spring XIME
@Service, @Autowired - DI driven by annotations Directory layout plus constructor type hints. No annotation is read for DI
@Transactional - AOP proxies rewriting your call async with self.transaction(): - the boundary is a line of code you can see
Prototype, request and session scopes One scope: eager singleton. That is why the whole graph can be checked at startup

So "Spring Boot for Python" is the wrong shorthand. The right one is one dependency graph, many front doors - and one of those doors opens onto industrial hardware.


Why not dependency-injector, injector, or lagom?

These are solid libraries. XIME used to lean on dependency-injector for its singleton storage layer, but as of 0.6 the registry is hand-rolled (a plain dict keyed by the class object), so XIME has no third-party DI dependency at all. The difference is scope:

dependency-injector / injector lagom XIME
Auto-scan packages by directory No - manual wiring required No Yes
Startup-time graph validation No Partial Yes - cycles, missing impl, ambiguous bindings
Code-first gRPC generation No No Yes
Web framework integration No No Yes - controllers, middleware, lifecycle
Explicit transaction management No No Yes - async with self.transaction():
Designed for microservice structure No No Yes

If you only need DI, use dependency-injector or lagom. If you want a full convention layer that wires DI, HTTP, gRPC, transactions, and lifecycle together - use XIME.


How It Works

Application Code
      ↓
   XIME Core          ← scanning, DI, lifecycle, config
      ↓
  DI Container        ← core/container, built-in
      ↓
Python Objects

XIME's startup pipeline:

  1. Load framework configuration (config/dependency.py)
  2. Load runtime configuration (resources/application.yml)
  3. Scan declared packages
  4. Resolve type hints
  5. Build dependency graph
  6. Validate graph - detect cycles, missing implementations, ambiguous bindings
  7. Create singletons
  8. Start adapters (FastAPI, gRPC, ...)

If anything is wrong, the app fails immediately at startup with a clear error - not later in production.


Installation

pip install xime

Adapters and starters are optional - install only what you need:

pip install "xime[web]"          # Uvicorn ASGI server
pip install "xime[sqlalchemy]"   # async DB sessions + transactions
pip install "xime[jwt]"          # JWT authentication
pip install "xime[scheduler]"    # cron-style task scheduling
pip install "xime[redis]"        # Redis client + cache backend
pip install "xime[grpc]"         # gRPC adapter (code-first)
pip install "xime[socket]"       # Unix domain socket IPC
pip install "xime[mqtt]"         # MQTT adapter (pub/sub + RPC over MQTT v5)
pip install "xime[s3]"           # S3 / MinIO storage backend
pip install "xime[mail]"         # SMTP email sending (aiosmtplib)
pip install "xime[modbus]"       # Modbus TCP adapter (master + slave)
pip install "xime[opcua]"        # OPC UA adapter (client + server)
pip install "xime[all]"          # everything above

Requires Python 3.12+.


Quick Start

1. Define a controller - a plain class; methods map to routes.

# app/api/rest/user_controller.py
from xime.adapters.web.routing import get

class UserController:
    prefix = "/users"

    def __init__(self, use_case: GetUserUseCase) -> None:
        self._use_case = use_case

    @get("/{user_id}", response_model=UserResponse)
    async def get_user(self, user_id: int) -> UserResponse:
        return await self._use_case.execute(user_id)

2. Configure dependency injection - declare which packages to scan and bind interfaces to implementations.

# app/config/dependency.py
from xime import BindingConfig

dependency = BindingConfig()
dependency.scan("application.usecase", "infrastructure.repository")
dependency.bind({UserRepository: JpaUserRepository})

3. Bootstrap the application.

# app/main.py
from xime import Application
from xime.adapters.web import WebAdapter

app = Application()
app.use(WebAdapter())
app.run()

4. Run it.

python -m app.main
Going further - multiple protocols & servers
# REST + gRPC simultaneously
from xime import Application
from xime.adapters.web import WebAdapter
from xime.adapters.grpc import GrpcAdapter

app = Application()
app.use(WebAdapter())
app.use(GrpcAdapter())
app.run()
# Multiple servers in one process (public API + internal admin)
from xime import Application
from xime.adapters.web import WebAdapter

app = Application()
app.use(WebAdapter())                              # server_id="default", port from application.yml
app.use(WebAdapter("admin", "127.0.0.1", 8081))   # server_id="admin", explicit host/port
app.run()

📦 Example Projects

The best way to learn XIME is to read real code. These open-source projects are built on the framework - clone them, run them, and use them as references for structuring your own service:

Project What it demonstrates Good for
xime-shop-example An e-commerce demo using a straightforward layered architecture. 🟢 Getting started
data-service A production-grade microservice: Hexagonal / DDD, gRPC, SQLAlchemy, multi-tenant sharding. The most complete reference. 🔵 Real-world patterns
notification-service An async, IO-bound notification microservice with event-driven patterns. 🔵 Async & events
xime-grpc-socket-example One app serving gRPC (code-first, dynamic mTLS) and Unix Domain Sockets side by side, with shared @command / @stream contracts and different security models. 🟣 Multi-transport

New to XIME? Start with xime-shop-example for the fundamentals, then study data-service for full Hexagonal/DDD patterns at production scale. To see one app speak gRPC and sockets at once, read xime-grpc-socket-example.


Features

Feature Description
Constructor Injection Declare dependencies as constructor params - XIME wires them
Directory-Driven DI Package location determines component role - no annotations
Interface Binding Explicit Protocol → implementation mapping, validated at startup
Dynamic Binding Bind one Protocol to several impls (a tuple) and swap them app-wide at runtime via Switcher; off by default, consumers keep their code
Fail Fast Circular deps, missing implementations, ambiguous bindings → startup error
Lifecycle Hooks PostConstruct, PreDestroy for managed startup/shutdown
Initialization Order dependency.order([A, B, C]) - control post_construct() execution order across independent classes
Multi-Server Multiple WebAdapter / GrpcAdapter / SocketAdapter per process, each with its own server_id
Event Bus Internal pub/sub for decoupled domain events
Request Context Per-request data via ContextVar, set by adapters
Security Context AuthenticationManager, AuthorizationManager in core
Two-Layer Config Framework config (Python) + Runtime config (YAML)
Transaction API Explicit async with self.transaction(): - no hidden AOP; async with self.read_only(): for reads
Class-Based Controllers Controllers are DI singletons, methods map to routes
Code-First gRPC Write Python DTOs, XIME generates .proto + stubs; field-number stability via lock file; typed server streaming with @stream + yield (no chunk wrapper, so a Java peer reads the .proto and understands it)
gRPC Client SDK Generate a typed Pydantic client from .proto, inject via DI; deadlines, typed errors, automatic retry
HTTPS TLS for the HTTP server via a server.ssl block in application.yml, including client-certificate verification; misconfiguration stops startup instead of silently serving plain HTTP
Dynamic mTLS Certificate rotation without restart for both inbound servers and outbound clients
Peer Identity gRPC reads the verified client cert into request context (fail-soft): current_caller() gives the CN, current_peer_sans() every Subject Alternative Name - raw and uninterpreted, so you match your own scheme (SPIFFE IDs or otherwise)
Socket Adapter Unix Domain Socket IPC for same-host Native Engine calls (Linux); @command / @stream
MQTT Adapter Message-driven transport for IoT/embedded: @subscribe (pub/sub) + @rpc (request/reply over MQTT v5); auto-reconnect; bounded concurrency
Modbus Adapter Talk to PLCs directly: declarative device model that decodes registers (endianness, word order, scale), safe read planning, @poll / @on_change, and slave mode (@serve / @on_write)
OPC UA Adapter Client and server for the modern industrial protocol: node models, real subscriptions (@on_node_change), all three security levels
File Storage Backend-neutral StorageService (local filesystem / S3 / MinIO); bytes + streaming APIs; HTTP Range download and chunked upload helpers
Multi-process share_load() turns one app into a supervised cluster: the processes: block decides which process opens which port, the parent holds the listening sockets, run_once() runs exactly once cluster-wide, and a watchdog restarts a silent child then promotes a new primary
Shared Reference Data RefData - one copy in shared memory for data that has a durable source (JWT keys, app registry): the primary publishes, every process reads with no round trip
Inter-process Store Store on LMDB for state with no durable source - rate limits, passkey challenges, replay protection; survives a process restart, and needs no Redis
Inter-process Bus ProcessLink - commands and questions between processes, four distinct ask outcomes, per-channel ordering, each process owning its own write region
Health Endpoints Opt-in /healthz and /readyz reporting per-process and cluster state; off by default, so nothing is exposed unless you ask for it
Command-line Tools xime init scaffolds a project · xime config --print prints every key with its default · xime check config catches typos · xime check module-level catches work done at import time

Starters

Optional modules, similar to spring-boot-starter-*:

Starter What it provides Status
xime.starters.sqlalchemy Async DB session, SqlAlchemyTransactionManager, SqlAlchemyReadOnlyManager (read-only blocks), CrudRepository (built-in CRUD) ✅ Implemented
xime.starters.jwt JWT signing, verification, middleware, keys rotated by kid ✅ Implemented
xime.starters.scheduler Cron-style task scheduling ✅ Implemented
xime.starters.cache CacheService abstraction (backend-neutral) ✅ Implemented
xime.starters.redis Async Redis client + CacheService backend ✅ Implemented
xime.starters.storage StorageService abstraction (object/blob store) ✅ Implemented
xime.starters.localfs Local filesystem StorageService backend ✅ Implemented
xime.starters.s3 S3 / MinIO StorageService backend (multipart, presigned URL) ✅ Implemented
xime.starters.mail MailService abstraction + SMTP backend (async, HTML + text) ✅ Implemented

Design Principles

  • Explicit over implicit - binding, routing, config are always declared, never auto-discovered by magic
  • Constructor injection only - no @inject, no field injection, no @autowired
  • No annotations for roles - @service, @repository, @component do not exist; directory determines role
  • Fail fast - errors surface at startup, not at runtime
  • Thin wrapper - XIME does not rewrite FastAPI, SQLAlchemy, or gRPC; it orchestrates them

Project Status

XIME is in active development. The following are implemented: core DI (hand-rolled singleton registry, no third-party DI dependency) with dynamic interface binding (one Protocol → many impls, swapped at runtime), lifecycle, event bus, security context, configuration, JWT starter (audience/issuer enforcement, keysets addressed by kid, clock leeway, required claims), scheduler starter, SQLAlchemy starter, Cache + Redis starters, Storage starter (local filesystem + S3/MinIO) with HTTP file streaming (Range download, chunked upload), Web adapter (FastAPI + routing, pure-ASGI request-context & JWT middleware, custom middleware & exception handlers, DI/config-aware middleware via Inject/FromConfig markers + first-class configure_cors), gRPC adapter (proto-first + code-first, typed server streaming, dynamic mTLS), gRPC client SDK (typed, DI-injected, deadlines + typed errors + automatic retry), Socket adapter (Unix Domain Socket IPC), MQTT adapter (pub/sub + RPC over MQTT v5), Modbus adapter (declarative device model, master polling + slave mode), OPC UA adapter (node models, subscriptions, server mode, full security), multi-server support, WebSocket (@ws routing, handshake authentication over Sec-WebSocket-Protocol, close-on-token-expiry), and initialization order (dependency.order()).

0.8 adds a multi-process runtime: share_load() with a supervisor, watchdog and primary promotion; RefData (shared memory for data that has a durable source); Store on LMDB (state that has none); ProcessLink (inter-process bus); opt-in /healthz and /readyz; and the xime init / xime config / xime check command-line tools.

The core is covered by 2500+ tests.

See the CHANGELOG for release history.


Documentation

Document Description
Getting Started First app in 5 minutes
Architecture How XIME is structured internally
Core Concepts DI, interface binding, scopes
Configuration Framework config + runtime YAML
Routing Class-based controllers, route decorators
Transaction Explicit transaction management + read-only blocks
Code-First gRPC Generate .proto from Python DTOs; field-number stability; xime grpc generate/check; dynamic mTLS
gRPC Client SDK Generate a typed client SDK; inject it via DI; deadlines, typed errors, retry, dynamic mTLS
WebSocket @ws routes, token in a subprotocol, authentication before the handler, close on token expiry
Socket Adapter Unix Domain Socket IPC for same-host Native Engine calls
MQTT Adapter Message-driven pub/sub + RPC over MQTT v5 for IoT/embedded
Modbus Adapter Declarative device models, read planning, polling and slave mode for PLCs
OPC UA Adapter Node models, subscriptions, server mode, and all three security levels
File Storage StorageService (local / S3 / MinIO) + HTTP Range download & chunked upload
Inter-process Store Key-value store on LMDB for state with no durable source: rate limiting, passkey challenges, deduplication
Shared reference data RefData - one copy in shared memory for JWT keys and the app registry: the primary publishes, every process reads
Inter-process Bus ProcessLink - commands and questions between processes, four ask outcomes, per-channel ordering
Command-line tools xime init scaffolds a project · xime config --print prints every key with its default · xime check config catches typos
Multi-process share_load() - the processes: block, shared ports, supervisor, run_once(), primary promotion, watchdog, /healthz, and two probes for module-level code
Event loop Which loop is running, uvloop on Linux, and why it makes REST ~10% slower while making open-connection work 11-38% faster
Starters SQLAlchemy, JWT, Scheduler, Cache, Redis, Storage (local / S3 + HTTP streaming)
Testing DI overrides, fakes, test utilities
Contributing How to contribute, roadmap

Contributing

XIME is a solo project that needs community help to grow. There is still ground to cover: multi-process runtime, CLI scaffolding, testing utilities, and more.

Ways to contribute:

  • Read the architecture docs to understand the design
  • Pick an open area from the roadmap
  • Open an issue to discuss a feature or bug
  • Submit a pull request

Please read CONTRIBUTING before opening a PR.


License

Released under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xime-0.8.3.tar.gz (831.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xime-0.8.3-py3-none-any.whl (642.2 kB view details)

Uploaded Python 3

File details

Details for the file xime-0.8.3.tar.gz.

File metadata

  • Download URL: xime-0.8.3.tar.gz
  • Upload date:
  • Size: 831.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for xime-0.8.3.tar.gz
Algorithm Hash digest
SHA256 7cccd5c6a0869a8634897992b452a124b5f8f6092a32ee2d4c7bae0f79484824
MD5 34f6634141ae69959db6d4f5a4fef2ed
BLAKE2b-256 0189c8e24f8efb40638006e9401cac16f26f49e3e4ff41aa2a75c66cadece0d3

See more details on using hashes here.

File details

Details for the file xime-0.8.3-py3-none-any.whl.

File metadata

  • Download URL: xime-0.8.3-py3-none-any.whl
  • Upload date:
  • Size: 642.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for xime-0.8.3-py3-none-any.whl
Algorithm Hash digest
SHA256 8596c6b7950a92608ceb5564468f6483614de33a5463483d66378b7eb901277e
MD5 a48c0d7ed85fd8863a8d71e9f21e16ef
BLAKE2b-256 56cf1bb9f2394b9f48f11a9d14e8420a0aa9978b653107892c11426b8004a317

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.8.3 This release

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page