MicroPie is a fast, lightweight, modern Python web framework that supports asynchronous web applications. Designed with flexibility and simplicity in mind, MicroPie enables you to handle high-concurrency applications with ease while allowing natural integration with external tools like Socket.IO for real-time communication.
- 🔄 Routing: Automatic mapping of URLs to functions with support for dynamic and query parameters.
- 🔒 Sessions: Simple, plugable, session management using cookies.
- 🎨 Templates: Jinja2, if installed, for rendering dynamic HTML pages.
- ⚙️ Middleware: Support for custom request middleware enabling functions like rate limiting, authentication, logging, and more.
- ✨ ASGI-Powered: Built w/ asynchronous support for modern web servers like Uvicorn, Hypercorn, and Daphne, enabling high concurrency.
- 🛠️ Lightweight Design: Only optional dependencies for flexibility and faster development/deployment.
- ⚡ Blazing Fast: Check out how MicroPie compares to other popular ASGI frameworks below!
- Homepage: patx.github.io/micropie
- API Reference: README.md#api-documentation
- PyPI Page: pypi.org/project/MicroPie
- GitHub Project: github.com/patx/micropie
- File Issue/Request: github.com/patx/micropie/issues
- Example Applications: github.com/patx/micropie/tree/main/examples
- Introduction Lightning Talk: Introduction to MicroPie on YouTube
Install MicroPie with all optional dependencies via pip:
This will install MicroPie along with jinja2 for template rendering, and multipart for parsing multipart form data.
If you would like to install all optional dependencies (everything from standard plus orjson and uvicorn) you can run:
You can also install MicroPie without ANY dependencies via pip:
For an ultra-minimalistic approach, download the standalone script:
Place it in your project directory, and you are good to go. Note that jinja2 must be installed separately to use the _render_template method and/or multipart for handling file data (the _parse_multipart method), but this is optional and you can use MicroPie without them. To install the optional dependencies use:
By default MicroPie will use the json library from Python's standard library. If you need faster performance you can use orjson. MicroPie will use orjson if installed by default. If it is not installed, MicroPie will fallback to json. This means with or without orjson installed MicroPie will still handle JSON requests/responses the same. To install orjson and take advantage of it's performance, use:
In order to test and deploy your apps you will need a ASGI web server like Uvicorn, Hypercorn or Daphne. Install uvicorn with:
You can also install MicroPie with uvicorn included using:
Save the following as app.py:
Run the server with:
Access your app at http://127.0.0.1:8000.
MicroPie automatically maps URLs to methods within your App class. Routes can be defined as either synchronous or asynchronous functions, offering good flexibility.
For GET requests, pass data through query strings or URL path segments, automatically mapped to method arguments.
Access:
- http://127.0.0.1:8000/greet?name=Alice returns Hello, Alice!, same as http://127.0.0.1:8000/greet/Alice returns Hello, Alice!.
- http://127.0.0.1:8000/hello/Alice returns a 500 Internal Server Error because it is expecting http://127.0.0.1:8000/hello?name=Alice, which returns Hello Alice!
MicroPie also supports handling form data submitted via HTTP POST requests. Form data is automatically mapped to method arguments. It is able to handle default values and raw/JSON POST data:
By default, MicroPie's route handlers can accept any request method, it's up to you how to handle any incoming requests! You can check the request method (and an number of other things specific to the current request state) in the handler withself.request.method. You can see how to handle POST JSON data at examples/api.
You can use middlware to add explicit routing when needed. See the middleware router example.
Because of its designed simplicity, MicroPie does not handle WebSockets out of the box. While the underlying ASGI interface can theoretically handle WebSocket connections, MicroPie’s routing and request-handling logic is designed primarily for HTTP. While MicroPie does not natively support WebSockets (yet!), you can easily integrate dedicated Websockets libraries like Socket.IO alongside Uvicorn to handle real-time, bidirectional communication. Check out examples/socketio to see this in action.
Dynamic HTML generation is supported via Jinja2. This happens asynchronously using Pythons asyncio library, so make sure to use the async and await with this method.
Here again, like Websockets, MicroPie does not have a built in static file method. While MicroPie does not natively support static files, if you need them, you can easily integrate dedicated libraries like ServeStatic or Starlette’s StaticFiles alongside Uvicorn to handle async static file serving. Check out examples/static_content to see this in action.
Support for streaming responses makes it easy to send data in chunks.
Built-in session handling simplifies state management:
You also can use the SessionBackend class to create your own session backend. You can see an example of this in examples/sessions.
MicroPie allows you to create pluggable middleware to hook into the request lifecycle. Take a look a trivial example using HttpMiddleware to send the console messages before and after the request is processed. Check out examples/middleware to see more.
MicroPie apps can be deployed using any ASGI server. For example, using Uvicorn if our application is saved as app.py and our App subclass is assigned to the app variable we can run it with:
The best way to get an idea of how MicroPie works is to see it in action! Check out the examples folder for more advanced usage, including:
- Template rendering
- Custom HTTP request handling
- File uploads
- Serving static content
- Session usage
- JSON Requests and Responses
- Socket.io Integration
- Async Streaming
- Middleware, including rate limiting and explicit routing
- Form handling and POST requests
- And more
| Routing | Automatic | Manual | Automatic | Manual | Views | Manual |
| Template Engine | Jinja2 (Opt.) | Jinja2 | Plugin | SimpleTpl | Django | Jinja2 |
| Middleware | Yes | Yes | Yes | Yes | Yes | Yes |
| Session Handling | Plugin | Extension | Built-in | Plugin | Built-in | Extension |
| Async Support | Yes | No (Quart) | No | No | Yes | Yes |
| Built-in Server | No | No | Yes | Yes | Yes | No |
The table below summarizes the performance of various ASGI frameworks based on a 15-second wrk test with 4 threads and 64 connections, measuring a simple "hello world" JSON response. Learn More.
| Blacksheep | 831,432 | 55,060.05 | 7.98 | 1.15 | 0.39 | 15.11 |
| MicroPie | 791,721 | 52,685.82 | 8.09 | 1.35 | 1.09 | 21.59 |
| Starlette | 779,092 | 51,930.45 | 7.03 | 1.22 | 0.39 | 17.42 |
| Litestar | 610,059 | 40,401.18 | 5.47 | 1.57 | 0.63 | 33.66 |
| FastAPI | 281,493 | 18,756.73 | 2.54 | 3.52 | 1.82 | 56.73 |
We welcome suggestions, bug reports, and pull requests!
- File issues or feature requests here.
- Security issues that should not be public, email harrisonerd [at] gmail.com.
MicroPie provides an abstraction for session backends, allowing you to define custom session storage mechanisms.
-
load(session_id: str) -> Dict[str, Any]
- Abstract method to load session data given a session ID.
-
save(session_id: str, data: Dict[str, Any], timeout: int) -> None
- Abstract method to save session data.
An in-memory implementation of the SessionBackend.
-
__init__()
- Initializes the in-memory session backend.
-
load(session_id: str) -> Dict[str, Any]
- Loads session data for the given session ID.
-
save(session_id: str, data: Dict[str, Any], timeout: int) -> None
- Saves session data for the given session ID.
MicroPie allows you to create pluggable middleware to hook into the request lifecycle.
-
before_request(request: Request) -> None
- Abstract method called before the request is processed.
-
after_request(request: Request, status_code: int, response_body: Any, extra_headers: List[Tuple[str, str]]) -> None
- Abstract method called after the request is processed but before the final response is sent to the client.
Represents an HTTP request in the MicroPie framework.
- scope: The ASGI scope dictionary for the request.
- method: The HTTP method of the request.
- path_params: List of path parameters.
- query_params: Dictionary of query parameters.
- body_params: Dictionary of body parameters.
- get_json: JSON request body object.
- session: Dictionary of session data.
- files: Dictionary of multipart data/streamed content.
- headers: Dictionary of headers.
The main ASGI application class for handling HTTP requests in MicroPie.
-
__init__(session_backend: Optional[SessionBackend] = None) -> None
- Initializes the application with an optional session backend.
-
request -> Request
- Retrieves the current request from the context variable.
-
__call__(scope: Dict[str, Any], receive: Callable[[], Awaitable[Dict[str, Any]]], send: Callable[[Dict[str, Any]], Awaitable[None]]) -> None
- ASGI callable interface for the server. Checks scope type.
-
_asgi_app_http(scope: Dict[str, Any], receive: Callable[[], Awaitable[Dict[str, Any]]], send: Callable[[Dict[str, Any]], Awaitable[None]]) -> None
- ASGI application entry point for handling HTTP requests.
-
request(self) -> Request
- Accessor for the current request object. - Returns the current request from the context variable.
-
_parse_cookies(cookie_header: str) -> Dict[str, str]
- Parses the Cookie header and returns a dictionary of cookie names and values.
-
_parse_multipart(reader: asyncio.StreamReader, boundary: bytes) -> Tuple[Dict[str, List[str]], Dict[str, Dict[str, Any]]]
- Asynchronously parses multipart/form-data from the given reader using the specified boundary. Returns a tuple of two dictionaries: form_data (text fields as key-value pairs) and files (file fields with metadata). Each file entry in files contains:
- filename: The original filename of the uploaded file.
- content_type: The MIME type of the file (defaults to application/octet-stream).
- content: An asyncio.Queue containing chunks of file data as bytes, with a None sentinel signaling the end of the stream.
- Handlers can consume the file data by iterating over the queue (e.g., using await queue.get()).
- Requires: multipart
- Asynchronously parses multipart/form-data from the given reader using the specified boundary. Returns a tuple of two dictionaries: form_data (text fields as key-value pairs) and files (file fields with metadata). Each file entry in files contains:
-
_send_response(send: Callable[[Dict[str, Any]], Awaitable[None]], status_code: int, body: Any, extra_headers: Optional[List[Tuple[str, str]]] = None) -> None
- Sends an HTTP response using the ASGI send callable.
-
_redirect(location: str) -> Tuple[int, str]
- Generates an HTTP redirect response.
-
_render_template(name: str, **kwargs: Any) -> str
- Renders a template asynchronously using Jinja2.
- Requires: jinja2
The App class is the main entry point for creating MicroPie applications. It implements the ASGI interface and handles HTTP requests.
Handlers can return responses in the following formats:
- String or bytes or JSON
- Tuple of (status_code, body)
- Tuple of (status_code, body, headers)
- Async or sync generator for streaming responses
MicroPie provides built-in error handling for common HTTP status codes:
- 404 Not Found: Automatically returned for non-existent routes
- 400 Bad Request: Returned for missing required parameters
- 500 Internal Server Error: Returned for unhandled exceptions
Custom error handling can be implemented through middleware.
© 2025 Harrison Erd
.png)

