Streaming Responses and Server-Sent Events in FastAPI

A
Author
31 May, 2026 1 min read 455 views

Some responses shouldn't wait until everything is ready: large exports, progress updates, or text from an LLM. FastAPI's StreamingResponse sends data as your generator produces it.

Streaming a large CSV

from fastapi.responses import StreamingResponse

@app.get("/export/orders.csv")
async def export_orders(db: DbSession):
    async def rows():
        yield "id,total,created_at\n"
        result = await db.stream(select(Order.id, Order.total, Order.created_at))
        async for r in result:
            yield f"{r.id},{r.total},{r.created_at.isoformat()}\n"

    return StreamingResponse(rows(), media_type="text/csv",
                             headers={"Content-Disposition": "attachment; filename=orders.csv"})

Server-Sent Events

import asyncio, json

@app.get("/jobs/{job_id}/events")
async def job_events(job_id: str, request: Request):
    async def events():
        while True:
            if await request.is_disconnected():
                break
            status = await jobs.status(job_id)
            yield f"data: {json.dumps(status)}\n\n"
            if status["state"] in ("done", "failed"):
                break
            await asyncio.sleep(1)

    return StreamingResponse(events(), media_type="text/event-stream",
                             headers={"Cache-Control": "no-cache"})

Streaming LLM output

import anthropic

client = anthropic.AsyncAnthropic()

@app.post("/chat")
async def chat(body: ChatRequest):
    async def tokens():
        async with client.messages.stream(
            model="claude-opus-5-5",
            max_tokens=64000,
            messages=body.messages,
        ) as stream:
            async for text in stream.text_stream:
                yield f"data: {json.dumps({'delta': text})}\n\n"
        yield "data: [DONE]\n\n"

    return StreamingResponse(tokens(), media_type="text/event-stream")

Tips

  • Use async generators with async libraries so streaming doesn't block the event loop.
  • Disable buffering in proxies (for example X-Accel-Buffering: no for Nginx).
  • Check request.is_disconnected() to stop work when the client leaves.
Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.