Django
MEDIA_URL
MEDIA_ROOT
File Handling
Web Development

Django MEDIA_URL and MEDIA_ROOT

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

MEDIA_ROOT and MEDIA_URL are two of the most frequently confused Django settings. They solve different parts of the same problem: where uploaded files are stored and how those files are reached from a browser. Once you separate filesystem paths from public URLs, the distinction becomes clear.

MEDIA_ROOT Is a Filesystem Path

MEDIA_ROOT tells Django where uploaded files live on disk. It should be an absolute path pointing to a directory on the server.

A common setup in settings.py looks like this:

python
1from pathlib import Path
2
3BASE_DIR = Path(__file__).resolve().parent.parent
4
5MEDIA_ROOT = BASE_DIR / "media"
6MEDIA_URL = "/media/"

If a model has an ImageField(upload_to="avatars/"), Django stores the uploaded file somewhere under MEDIA_ROOT, such as:

text
/path/to/project/media/avatars/user1.png

That is storage, not a browser URL.

MEDIA_URL Is the Public URL Prefix

MEDIA_URL is the URL prefix used when building links to uploaded files. If MEDIA_URL = "/media/", then the file above would typically be reachable at:

text
/media/avatars/user1.png

That is why the two settings work together:

  • 'MEDIA_ROOT says where the file is stored'
  • 'MEDIA_URL says what URL prefix points to that storage'

They should not be the same kind of value. One is a filesystem path, the other is a URL prefix.

A Working Model Example

Here is a simple model using uploaded media:

python
1from django.db import models
2
3
4class Profile(models.Model):
5    avatar = models.ImageField(upload_to="avatars/")

When a file is uploaded, Django stores it under MEDIA_ROOT / "avatars" and the field can expose a URL through avatar.url, which is based on MEDIA_URL.

For example in a template:

django
{% if profile.avatar %}
  <img src="{{ profile.avatar.url }}" alt="User avatar">
{% endif %}

That is the normal flow: store with MEDIA_ROOT, render with MEDIA_URL.

Development Serving Is Separate

In development, Django can serve media files for you if you add the usual URL helper:

python
1from django.conf import settings
2from django.conf.urls.static import static
3from django.urls import path
4
5urlpatterns = [
6    # your routes here
7]
8
9if settings.DEBUG:
10    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

This is convenient for local development. It is not how production should usually work.

Production Uses a Real Web Server or Object Storage

In production, uploaded files are usually served by:

  • Nginx
  • Apache
  • a cloud object store such as S3
  • a CDN in front of that storage

Django should usually not serve large volumes of user-uploaded files itself. The settings still matter, but the actual serving path may be handled by infrastructure outside the Django process.

That is also why MEDIA_URL can point to a different domain entirely in some deployments, such as a CDN or storage bucket URL prefix.

Do Not Mix Media and Static Files

MEDIA_* is for user-uploaded content. STATIC_* is for application assets such as CSS, JavaScript, and bundled images.

That distinction matters because the lifecycle is different:

  • static files are built and deployed with the app
  • media files are created by users at runtime

Using the same directory or URL scheme for both is a common mistake and usually causes deployment confusion later.

Common Pitfalls

  • Setting MEDIA_ROOT to a URL instead of a filesystem path.
  • Setting MEDIA_URL to a local disk path instead of a browser-facing URL prefix.
  • Forgetting to configure media serving during development and then assuming uploads failed.
  • Using Django to serve media in production when a proper web server or storage backend should handle it.
  • Mixing media settings with static-file settings as if they solved the same problem.

Summary

  • 'MEDIA_ROOT is the absolute filesystem location for uploaded files.'
  • 'MEDIA_URL is the public URL prefix used to reach those files.'
  • Uploaded model fields usually store under MEDIA_ROOT and expose URLs under MEDIA_URL.
  • Django can serve media in development, but production usually delegates that to web infrastructure.
  • Keep media and static files conceptually and operationally separate.

Course illustration
Course illustration

All Rights Reserved.