Django
MEDIA_URL
MEDIA_ROOT
File Handling
Web Development

Django MEDIA_URL and MEDIA_ROOT

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

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.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.