python
44 lines · 9 steps
Streaming a CSV export in Flask
Generate and stream a large CSV download row by row so the whole dataset never sits in memory at once.
Explained by
highlit
1import csv
2import io
3from datetime import datetime
4
5from flask import Blueprint, Response, stream_with_context
6
7from .models import Order
8
9exports = Blueprint("exports", __name__)
10
11
12@exports.route("/exports/orders.csv")
13def export_orders():
14 columns = ["id", "reference", "customer_email", "total_cents", "status", "placed_at"]
15
16 def generate():
17 buffer = io.StringIO()
18 writer = csv.writer(buffer)
19
20 writer.writerow(columns)
21 yield buffer.getvalue()
22 buffer.seek(0)
23 buffer.truncate(0)
24
25 query = Order.query.order_by(Order.id).yield_per(500)
26 for order in query:
27 writer.writerow([
28 order.id,
29 order.reference,
30 order.customer_email,
31 order.total_cents,
32 order.status,
33 order.placed_at.isoformat(),
34 ])
35 yield buffer.getvalue()
36 buffer.seek(0)
37 buffer.truncate(0)
38
39 filename = f"orders-{datetime.utcnow():%Y%m%d}.csv"
40 headers = {
41 "Content-Type": "text/csv; charset=utf-8",
42 "Content-Disposition": f'attachment; filename="{filename}"',
43 }
44 return Response(stream_with_context(generate()), headers=headers)
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A generator paired with a streaming Response lets you send arbitrarily large files without buffering them fully in memory.
- 2Reusing one StringIO buffer and truncating it after each yield keeps per-row memory flat.
- 3yield_per fetches database rows in batches so a huge table doesn't load all at once.
Related explainers
python
import argparse import sys from pathlib import Path
Building a subcommand CLI with argparse
cli
argparse
subcommands
Intermediate
6 steps
python
from collections.abc import Mapping from typing import Any, Iterator
Flattening nested config into dotted keys
recursion
generators
tree-traversal
Intermediate
7 steps
javascript
const express = require('express'); const v1 = express.Router();
Versioning an API with Express Routers
api versioning
routing
modularity
Intermediate
10 steps
python
import time from collections import defaultdict from threading import Lock
Sliding-window login rate limiting in Flask
rate-limiting
sliding-window
thread-safety
Intermediate
7 steps
python
from django.conf import settings from django.contrib.auth import get_user_model from django.core.mail import EmailMultiAlternatives from django.db.models.signals import post_save
Sending a welcome email with Django signals
signals
email
user-activation
Intermediate
8 steps
python
import csv import io from datetime import date
Streaming a CSV export in FastAPI
streaming
async-generators
csv
Advanced
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/streaming-a-csv-export-in-flask-explained-python-0c6e/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.