Search Topics

Search across all FastAPI topics

GitHub

Background Tasks

Core Concept

Your user waited 5 seconds for a signup that should have taken 200ms. Let's fix that.

A user signs up. Your endpoint sends a welcome email synchronously. The SMTP server takes 5 seconds to respond. The user stares at a loading spinner for 5 seconds just to see "Registration successful".

terminal
POST /signup {"email": "alice@example.com", "name": "Alice"}

# Server timeline:
# 0.0s — Receive request
# 0.1s — Create user in DB ✓
# 0.2s — Start sending welcome email...
# 5.2s — Email sent ✓
# 5.2s — Return response

# User waited 5.2 seconds for a 0.1-second operation.
# Response time: 5,200ms (should be ~200ms)

Question

Think about it: the user's account was created in 100ms. Everything after that — the email, the logging, the admin notification — the user doesn't need to wait for any of it. So why are you making them?

The Idea: Respond First, Work Later

Background tasks let you send the response immediately and do the slow stuff after the user has already moved on. Here's the flow:

Request arrives

POST /signup

Create user

~100ms

Queue tasks

Email, logging...

Send response

User sees success!

Run tasks

After response sent

the core concept

What you just learned

Background tasks run AFTER the response is sent — the user never waits

You queue tasks during request handling, but they execute after the response

Perfect for emails, logging, notifications — anything the user doesn't need to see immediately

Your First Background Task

FastAPI has this built in. Just inject BackgroundTasks and add functions to it. They'll run after the response is sent.

main.py
from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def send_email(email: str, message: str):
    # This could take 5 seconds — doesn't matter!
    # The user already got their response.
    print(f"Sending email to {email}: {message}")

@app.post("/signup")
async def signup(email: str, background_tasks: BackgroundTasks):
    # Step 1: Do the fast stuff
    # create_user(email)  # ~100ms

    # Step 2: Queue the slow stuff
    background_tasks.add_task(send_email, email, "Welcome!")

    # Step 3: Respond immediately
    return {"message": "User created, email will be sent"}
    # ← Response goes out NOW. Email sends AFTER.

Insight

Notice the function signature: background_tasks: BackgroundTasks. FastAPI sees that type hint and automatically injects the background task manager. You don't create it yourself. Just declare it and use it.

Queuing Multiple Tasks

You can queue as many tasks as you want. They run sequentially in the order you added them — one finishes, the next starts.

main.py
def write_log(message: str):
    with open("log.txt", "a") as f:
        f.write(f"{message}\n")

def notify_admin(user_email: str):
    send_email("admin@example.com", f"New signup: {user_email}")

@app.post("/signup")
async def signup(email: str, background_tasks: BackgroundTasks):
    # Queue them up — they run in this order AFTER response
    background_tasks.add_task(send_email, email, "Welcome!")
    background_tasks.add_task(write_log, f"New user: {email}")
    background_tasks.add_task(notify_admin, email)

    return {"message": "Signup complete"}
    # User gets this instantly. Three tasks run behind the scenes.

basic background tasks

What you just learned

add_task() takes a function and its arguments — the function runs after the response

Multiple tasks run sequentially in the order they were added

The response time is now independent of how many background tasks you queue

Go Deeper: Tasks in Dependencies

Here's something neat: your dependencies can also queue background tasks. FastAPI uses the same BackgroundTasks instance across your endpoint and all its dependencies.

main.py
async def log_request(
    background_tasks: BackgroundTasks,
    q: str | None = None,
):
    if q:
        # This dependency queues a background task
        background_tasks.add_task(write_log, f"Query: {q}")

@app.get("/items")
async def list_items(
    background_tasks: BackgroundTasks,
    q: str | None = Depends(log_request),
):
    # Your endpoint adds its own task too
    background_tasks.add_task(write_log, "Items listed")
    return items
    # Both tasks run after the response — dep's task first

Watch out

Background tasks run in the same process as your API. If a background task hogs the CPU or crashes, it can affect your API's performance. For heavy workloads (processing videos, sending thousands of emails), use a proper task queue like Celery or Dramatiq instead.

See It: Background Task Flow

Watch how FastAPI sends the response immediately, then runs email, logging, and notification tasks in the background — the client never waits.

Think about it...

If a background task raises an exception after the response was already sent, does the user see a 500 error?

Hint: Think about the timeline: when does the response leave vs when does the task run?

Key Points

After Response

Tasks run after the response is sent — no client waiting

Sequential

Multiple tasks run in the order they were added

In-Process

Runs in the same process — use Celery for heavy workloads

Use Cases

Email, logging, cache invalidation, webhook notifications