15 min read - November 28, 2025

Learn how to build a full-stack web application using Django for the backend and React for the frontend, with step-by-step guidance.
Looking to create a web app with a strong backend and dynamic frontend? Pairing Django, a Python framework, with React, a JavaScript library, is a great way to achieve this. Django handles backend tasks like database management and API creation, while React creates a responsive, interactive user interface.
Key Steps:
python --version, node --version, and npm --version.django-admin startproject for backend setup and npx create-react-app for frontend initialization.django-cors-headers to enable communication between frontend and backend.localhost:8000 and React on localhost:3000.This setup allows you to efficiently build a full-stack application with clear separation between backend and frontend. Follow these steps to create a scalable, interactive web app.
Before you start building your Django and React app, it's crucial to set up your development environment with the necessary tools and dependencies. This foundation will help you create, integrate, and test your Django and React components smoothly as you proceed.
To get started, your development machine will need Python 3.x for Django and Node.js for React. Specifically, Django 5.0 requires Python 3.x, while React works with Node.js version 12 or higher.
Installing Python: You can download Python directly from its official website or use your system's package manager. For macOS users, Homebrew makes it simple with brew install python. Windows users should grab the installer from python.org, while Linux users can install it with commands like apt install python3 on Ubuntu or similar commands for other distributions.
Setting Up Node.js and npm: Node.js comes bundled with npm (Node Package Manager). You'll need npm version 6 or higher, with version 7.5.4 being a reliable choice. Download Node.js from nodejs.org, which will automatically include npm.
Python Virtual Environments: Using virtual environments is key to managing project-specific dependencies without conflicts. You can use the built-in venv module or tools like pipenv or virtualenvwrapper for more features. If you're on Windows, the virtualenvwrapper-win package provides similar functionality.
To confirm your installations, run these commands in your terminal:
python --version
node --version
npm --version
A well-organized project structure is essential for keeping your backend and frontend code separate and manageable. Start by creating a main directory for your project:
mkdir django-react-app
cd django-react-app
Inside this directory, create two folders: one for your Django backend and another for your React frontend. This separation allows you to maintain and deploy each part independently.
Set up your Python virtual environment within the project directory:
python -m venv venv
Activate the virtual environment:
source venv/bin/activatevenv\Scripts\activateThis step ensures that all Python dependencies for your project are isolated.
With your environment ready, it's time to install the necessary packages for both Django and React.
Django Backend Packages: While your virtual environment is active, install Django and its supporting libraries using pip:
pip install django
pip install djangorestframework
pip install django-cors-headers
React Frontend Setup: To set up your React environment, use the create-react-app tool. This command initializes a React project and installs all necessary dependencies:
npx create-react-app frontend
This will create a new React project in a frontend directory, complete with essential packages, development tools, and build scripts.
Additional Frontend Package: After setting up your React project, navigate into the frontend directory and install Axios, a library for making HTTP requests to your Django API:
cd frontend
npm install axios
At this point, your development environment is fully equipped with Python 3.x, Django, Node.js, React, and all the necessary tools. The Python virtual environment ensures your backend dependencies are isolated, while npm handles your JavaScript packages separately. Now you're ready to start building your full-stack application!
Set up a Django backend with database models, API endpoints, and integration for a React frontend.
Start by creating a Django project, which includes settings, database configurations, and app-specific options. Inside this project, you’ll build a Django app - a Python package designed for specific tasks like managing user data or content.
Navigate to your project’s root directory (where your virtual environment is set up) and create the Django project:
django-admin startproject backend .
This command generates project files directly in the current directory, avoiding an extra folder. You’ll notice new files like manage.py (for running Django commands) and a backend directory containing files like settings.py, urls.py, asgi.py, and wsgi.py.
Next, create an app to handle specific functionality. For instance, a task management system:
python manage.py startapp tasks
This creates a tasks directory with essential files like models.py, views.py, admin.py, and a migrations folder. Be sure to avoid naming conflicts with built-in names like "django" or "test."
Register the app in your project settings by adding it to the INSTALLED_APPS list in backend/settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'tasks', # Register your app
]
Define your data structure with Django models. For example, a simple Task model for the task management app can be added in tasks/models.py:
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
This model includes fields like CharField for short text, TextField for longer content, BooleanField for true/false values, and DateTimeField for timestamps. The Meta class specifies options like default ordering.
Apply the model to your database by running migrations:
python manage.py makemigrations tasks
python manage.py migrate
To convert model data to JSON, use Django REST Framework serializers. In tasks/serializers.py, define a serializer for the Task model:
from rest_framework import serializers
from .models import Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ['id', 'title', 'description', 'completed', 'created_at', 'updated_at']
read_only_fields = ['created_at', 'updated_at']
The ModelSerializer automatically generates fields and methods based on the model. Explicitly listing fields ensures you don’t unintentionally expose sensitive data.
Django REST Framework simplifies API creation. For standard CRUD operations, use ViewSets with routers for a clean, RESTful structure.
In tasks/views.py, create API views:
from rest_framework import viewsets
from rest_framework.permissions import AllowAny
from .models import Task
from .serializers import TaskSerializer
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
permission_classes = [AllowAny] # For development only
The ModelViewSet automatically handles listing, creating, retrieving, updating, and deleting tasks.
Set up URL routing in tasks/urls.py:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import TaskViewSet
router = DefaultRouter()
router.register(r'tasks', TaskViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Include these URLs in the main backend/urls.py file:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('tasks.urls')),
]
To allow your React frontend (running on port 3000) to communicate with the Django backend (on port 8000), configure Cross-Origin Resource Sharing (CORS). Without this, browsers block cross-origin requests for security reasons.
Update backend/settings.py to include CORS configuration:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # Add this at the top
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# CORS settings for development
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", # React development server
"http://127.0.0.1:3000",
]
CORS_ALLOW_CREDENTIALS = True
For quick testing, you can use CORS_ALLOW_ALL_ORIGINS = True, but specifying allowed origins is safer.
Before integrating the React frontend, test the API endpoints to ensure they work as expected. Start the Django development server:
python manage.py runserver
Access the API at http://127.0.0.1:8000/api/tasks/. Use the browsable API to test operations like GET and POST requests.
Alternatively, test with cURL or Postman:
# Test GET request to list tasks
curl -X GET http://127.0.0.1:8000/api/tasks/
# Test POST request to create a task
curl -X POST http://127.0.0.1:8000/api/tasks/ \
-H "Content-Type: application/json" \
-d '{"title": "Test Task", "description": "This is a test task"}'
For automated testing, add test cases in tasks/tests.py:
from rest_framework.test import APITestCase
from rest_framework import status
from .models import Task
class TaskAPITestCase(APITestCase):
def test_create_task(self):
# Add your assertions and test logic here
pass
With the backend in place, you’re ready to connect it to the React frontend.
To create an engaging interface for your Django backend, you'll use React to manage user interactions - everything from viewing tasks to adding new ones.
Start by setting up your React frontend using Create React App. Navigate to your project’s root directory (where your Django backend lives) and run:
npx create-react-app frontend
cd frontend
This command sets up a React app with essential files like package.json, src/App.js, and public/index.html. It also includes tools like webpack for bundling, Babel for JavaScript compilation, and a development server for testing.
Next, install Axios for handling HTTP requests to your Django API:
npm install axios
Axios makes API calls simpler by managing JSON parsing and offering better error handling than the built-in fetch() function. It also supports features like request and response interceptors.
Your folder structure should now look like this:
project-root/
├── backend/
│ ├── manage.py
│ ├── backend/
│ └── tasks/
└── frontend/
├── package.json
├── public/
└── src/
To confirm everything is working, start the React development server:
npm start
This launches the app at http://localhost:3000, displaying the default React welcome page. Keep this server running during development - it automatically reloads when you make changes.
Let’s create a TaskList component to display tasks fetched from your Django API. Add the following to src/components/TaskList.js:
import React from 'react';
const TaskList = ({ tasks, onToggleComplete, onDeleteTask }) => {
return (
<div className="task-list">
<h2>Your Tasks</h2>
{tasks.length === 0 ? (
<p>No tasks available. Create your first task!</p>
) : (
<ul>
{tasks.map((task) => (
<li key={task.id} className={`task-item ${task.completed ? 'completed' : ''}`}>
<div className="task-content">
<h3>{task.title}</h3>
<p>{task.description}</p>
<small>Created: {new Date(task.created_at).toLocaleDateString()}</small>
</div>
<div className="task-actions">
<button
onClick={() => onToggleComplete(task.id, !task.completed)}
className={task.completed ? 'btn-undo' : 'btn-complete'}
>
{task.completed ? 'Undo' : 'Complete'}
</button>
<button
onClick={() => onDeleteTask(task.id)}
className="btn-delete"
>
Delete
</button>
</div>
</li>
))}
</ul>
)}
</div>
);
};
export default TaskList;
Next, create a TaskForm component for adding new tasks. Add this to src/components/TaskForm.js:
import React, { useState } from 'react';
const TaskForm = ({ onAddTask }) => {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
if (!title.trim()) return;
setIsSubmitting(true);
try {
await onAddTask({ title: title.trim(), description: description.trim() });
setTitle('');
setDescription('');
} catch (error) {
console.error('Error adding task:', error);
} finally {
setIsSubmitting(false);
}
};
return (
<form onSubmit={handleSubmit} className="task-form">
<h2>Add New Task</h2>
<div className="form-group">
<input
type="text"
placeholder="Task title"
value={title}
onChange={(e) => setTitle(e.target.value)}
disabled={isSubmitting}
required
/>
</div>
<div className="form-group">
<textarea
placeholder="Task description (optional)"
value={description}
onChange={(e) => setDescription(e.target.value)}
disabled={isSubmitting}
rows="3"
/>
</div>
<button type="submit" disabled={isSubmitting || !title.trim()}>
{isSubmitting ? 'Adding...' : 'Add Task'}
</button>
</form>
);
};
export default TaskForm;
For some basic styling, create a src/App.css file and add:
.task-list {
margin: 20px 0;
}
.task-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 5px;
}
.task-item.completed {
background-color: #f0f8f0;
text-decoration: line-through;
opacity: 0.7;
}
.task-form {
background: #f9f9f9;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group input, .form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 3px;
}
.btn-complete, .btn-undo, .btn-delete {
margin-left: 10px;
padding: 5px 10px;
border: none;
border-radius: 3px;
cursor: pointer;
}
.btn-complete { background: #28a745; color: white; }
.btn-undo { background: #ffc107; color: black; }
.btn-delete { background: #dc3545; color: white; }
React hooks like useState and useEffect make it easy to manage state and interact with your Django backend. To centralize API calls, create a service file src/services/api.js:
import axios from 'axios';
const API_BASE_URL = 'http://127.0.0.1:8000/api';
const api = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
});
export const taskAPI = {
getTasks: () => api.get('/tasks/'),
createTask: (taskData) => api.post('/tasks/', taskData),
updateTask: (taskId, taskData) => api.put(`/tasks/${taskId}/`, taskData),
deleteTask: (taskId) => api.delete(`/tasks/${taskId}/`),
};
export default api;
Finally, integrate everything in src/App.js:
import React, { useState, useEffect } from 'react';
import TaskList from './components/TaskList';
import TaskForm from './components/TaskForm';
import { taskAPI } from './services/api';
import './App.css';
function App() {
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
try {
setLoading(true);
const response = await taskAPI.getTasks();
setTasks(response.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
// Additional methods for adding, updating, and deleting tasks would go here
}
With this setup, your React frontend is ready to handle tasks interactively while communicating seamlessly with your Django backend.

Tired of slow deployments or bandwidth limits? FDC Servers offers instant dedicated power, global reach, and flexible plans built for any scale. Ready to upgrade?
Unlock Performance NowNow that your backend and frontend are up and running, the next step is to ensure smooth communication between them. This involves setting up API endpoints, managing requests, and addressing any integration hiccups.
Your React app needs to know where to locate the Django API endpoints. To achieve this, update the src/services/api.js file with environment-specific configurations:
import axios from 'axios';
// Determine API base URL based on environment
const getApiBaseUrl = () => {
if (process.env.NODE_ENV === 'production') {
return process.env.REACT_APP_API_URL || 'https://your-production-domain.com/api';
}
return 'http://127.0.0.1:8000/api';
};
const API_BASE_URL = getApiBaseUrl();
const api = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
timeout: 10000, // 10 second timeout
});
export const taskAPI = {
getTasks: () => api.get('/tasks/'),
createTask: (taskData) => api.post('/tasks/', taskData),
updateTask: (taskId, taskData) => api.put(`/tasks/${taskId}/`, taskData),
deleteTask: (taskId) => api.delete(`/tasks/${taskId}/`),
};
export default api;
For production, add a .env file to your React project root with the following content:
REACT_APP_API_URL=https://your-production-domain.com/api
This setup ensures your React app can seamlessly interact with your Django backend, whether you're in a local development environment or deploying to production. With the API endpoints configured, you're ready to fetch and manipulate backend data.
Once the API configuration is set, you can perform CRUD operations to manage data between React and Django. Update src/App.js to handle these operations:
import React, { useState, useEffect } from 'react';
import TaskList from './components/TaskList';
import TaskForm from './components/TaskForm';
import { taskAPI } from './services/api';
import './App.css';
function App() {
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
try {
setLoading(true);
setError(null);
const response = await taskAPI.getTasks();
setTasks(response.data);
} catch (err) {
setError('Failed to fetch tasks. Please check your connection.');
console.error('Error fetching tasks:', err);
} finally {
setLoading(false);
}
};
const handleAddTask = async (taskData) => {
try {
const response = await taskAPI.createTask(taskData);
setTasks(prevTasks => [...prevTasks, response.data]);
} catch (err) {
console.error('Error adding task:', err);
throw err; // Re-throw to let TaskForm handle the error
}
};
const handleToggleComplete = async (taskId, completed) => {
try {
const taskToUpdate = tasks.find(task => task.id === taskId);
const updatedTaskData = { ...taskToUpdate, completed };
const response = await taskAPI.updateTask(taskId, updatedTaskData);
setTasks(prevTasks =>
prevTasks.map(task =>
task.id === taskId ? response.data : task
)
);
} catch (err) {
console.error('Error updating task:', err);
}
};
const handleDeleteTask = async (taskId) => {
if (!window.confirm('Are you sure you want to delete this task?')) {
return;
}
try {
await taskAPI.deleteTask(taskId);
setTasks(prevTasks => prevTasks.filter(task => task.id !== taskId));
} catch (err) {
console.error('Error deleting task:', err);
}
};
if (loading) {
return <div className="loading">Loading tasks...</div>;
}
return (
<div className="App">
<header className="App-header">
<h1>Task Manager</h1>
</header>
<main className="container">
{error && <div className="error-message">{error}</div>}
<TaskForm onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
onToggleComplete={handleToggleComplete}
onDeleteTask={handleDeleteTask}
/>
</main>
</div>
);
}
export default App;
This code handles task creation, updates, deletions, and error management. The UI updates immediately for a smooth user experience, and errors are managed gracefully by reverting changes or showing appropriate messages.
One of the most common hurdles when linking Django and React is dealing with CORS (Cross-Origin Resource Sharing) errors. These arise because browsers block requests between different origins for security reasons. During development, React typically runs on localhost:3000, while Django operates on localhost:8000, creating a cross-origin scenario.
To address CORS issues, ensure you've configured the CORS headers in your Django settings as outlined in the "Configuring CORS Headers" section. After making changes, restart your Django server to apply them.
Here are a couple of common API request errors and their solutions:
owner field was missing in the request. Always double-check that your frontend sends all required fields expected by the Django models.generics.RetrieveUpdateAPIView to generics.RetrieveUpdateDestroyAPIView to include support for DELETE requests.With your Django backend and React frontend connected, it’s time to launch both development servers and test the application. This involves running two servers simultaneously and ensuring that everything works together smoothly.
To run your Django-React application, you’ll need two terminal windows - one for each server. This setup allows the backend and frontend to operate independently while communicating through API calls.
Starting the Django Backend Server:
Activate your Python virtual environment:
source venv/bin/activate
Start the Django development server:
python manage.py runserver
The server will be available at http://127.0.0.1:8000/.
Starting the React Frontend Server:
Open a second terminal window and navigate to your React project directory:
cd frontend
Launch the React development server:
npm start
This will automatically open a browser window at http://localhost:3000/.
Once both servers are running, you can begin testing the functionality of your application.
With the servers up and running, and CORS and API endpoints properly configured, it’s time to validate the data flow between the frontend and backend.
Backend API Verification:
Test your Django API endpoints directly by visiting:
http://localhost:8000/api/tasks
This should display the Django REST Framework’s browsable API interface, where you can perform CREATE and READ operations.
Access the Django admin interface at:
http://localhost:8000/admin
Log in with your superuser credentials to create, edit, or delete tasks. You can also test UPDATE and DELETE operations by visiting:
http://localhost:8000/api/tasks/{id}
Frontend-Backend Integration Testing:
http://localhost:3000 and confirm it loads correctly, displaying tasks from the Django backend.If your app includes filters or other features, test them thoroughly to confirm tasks are displayed as expected.
If you encounter any issues during testing, here are some common fixes to try.
API Connection Errors:
http://localhost:8000 and React at http://localhost:3000.Check the proxy setting in your React project’s package.json file:
"proxy": "http://localhost:8000"
If you make changes, restart the React server.
Server Startup Issues:
If the Django server doesn’t start, check for missing migrations:
python manage.py makemigrations
python manage.py migrate
For React server issues, try reinstalling dependencies:
npm install
Data Flow Problems:
console.log() in React or print statements in Django views, to trace the data flow./api/tasks/).You’ve created a web app that combines Django and React, giving you a solid introduction to full-stack development. This project highlights essential concepts like separating the backend from the frontend, performing CRUD operations, and managing cross-origin requests using CORS settings. Along the way, you’ve worked with Django REST Framework to build APIs and used React hooks for state management - skills that allow for smooth integration between these two powerful tools.
Taking Your App to the Next Level
There’s plenty of room to expand your app’s functionality. For example, you can add JWT authentication using Django REST Framework to secure user data and API access. This would allow you to offer user-specific features and personalized experiences.
If your app needs real-time updates, consider using Django Channels to enable WebSocket support. This is perfect for features like live dashboards, chat systems, or notifications, turning your app into a more dynamic and interactive platform.
As your app grows, advanced data visualization becomes important. By combining React’s rendering capabilities with efficient backend data fetching, you’ll be able to handle and display complex datasets effectively.
Getting Ready for Production
When preparing your app for production, focus on deployment, security, and performance. While the current setup is great for local development, production environments require extra steps. These include setting up environment variables, optimizing your database, and implementing strong error-handling mechanisms.
These improvements build on the skills you’ve already developed - like API design, component-based architecture, and full-stack integration. By mastering these advanced techniques, you’ll be well-equipped to tackle enterprise-level projects and continue growing as a web developer.
Using Django for the backend and React for the frontend creates a strong blend for developing modern web applications. Django provides a solid framework packed with tools that streamline backend development, while React shines in building dynamic and interactive user interfaces.
This combination promotes a clean separation of responsibilities, which helps keep the codebase organized and easier to expand over time. React's component-based structure encourages the reuse of UI elements, and Django's REST Framework simplifies the process of building APIs, ensuring smooth communication between the frontend and backend. Together, they offer a fast, efficient, and user-centered approach to application development.
To address CORS issues between a React frontend and a Django backend, the django-cors-headers package is a handy solution. First, install it using pip. Then, in your settings.py file, add 'corsheaders' to the INSTALLED_APPS list. After that, include 'corsheaders.middleware.CorsMiddleware' at the very top of the MIDDLEWARE list to ensure proper middleware execution order.
During development, you can simplify things by setting CORS_ORIGIN_ALLOW_ALL = True in your settings.py. This allows requests from any origin. However, in a production environment, it's much safer to define specific trusted domains using the CORS_ALLOWED_ORIGINS setting. This approach helps maintain tighter security.
With this configuration, your React app can interact smoothly with your Django APIs while staying compliant with CORS requirements.
To prepare your Django and React app for production, start by adjusting your Django settings for a secure setup. This includes setting DEBUG to False and specifying the ALLOWED_HOSTS to control which domains can access your app. These changes are essential for protecting your application in a live environment.
Next, select a dependable hosting platform for your Django backend and static files. Make sure your infrastructure is built to handle production-level traffic and demands. For the React frontend, use the appropriate build tools to generate an optimized production build.
Once your React app is ready, set up a web server like Nginx to serve both the React frontend and the Django backend. Proper server configuration ensures your app runs efficiently and provides a seamless experience for users.
Before going live, thoroughly test your app in the production environment. This step helps identify and resolve any issues, ensuring your app performs reliably once it's launched.

Explore the best monitoring tools for dedicated servers and VPS in 2025, focusing on AI, automation, and real-time analytics.
12 min read - November 28, 2025

Flexible options
Global reach
Instant deployment
Flexible options
Global reach
Instant deployment