Monorepos are back: building modern web apps with Django and React
Your startup spent three weeks building an MVP. The Django backend works, the React frontend looks great, and deployment day arrives. Then reality hits: the frontend needs different API URLs for staging and production, CORS breaks mysteriously, you're managing two CI/CD pipelines, and the frontend expects userPreferences while the backend sends user_preferences.
This is the multirepo tax: the hidden cost of splitting applications across separate repositories. After years of industry pressure toward microservices and separation, development teams are rediscovering that keeping code together is often smarter. Monorepos are making a comeback, and companies like Uber, Airbnb, and Pinterest have shared their journeys back to monolithic repositories after facing coordination challenges.
At Vinta, we've used monorepos across client projects for over a decade and built tooling to make this approach seamless for Django and React applications. In this article, we'll explore why monorepos are regaining popularity and how the Django-React Boilerplate provides a production-ready foundation for modern web development.
While this article focuses on Django and React, the same ideas apply to other Python stacks. For teams using FastAPI instead of Django, we also maintain a FastAPI + Next.js template with similar type generation capabilities.
Why developers are returning to monorepos
A monorepo is a single version-controlled repository containing multiple projects or components. Unlike a monolith, which is a tightly coupled application, a monorepo maintains logical separation while keeping code physically co-located.
Atomic commits and refactoring: In multirepo setups, large-scale changes require coordinating multiple pull requests and carefully timing deployments. Need to rename an API endpoint? That's a backend PR, a frontend PR, and a deployment window where things might break. In monorepos, one atomic commit contains all changes (backend updates, TypeScript type generation, frontend components, and routes) merged or reverted as a single unit.
Simplified dependency management: Version conflicts disappear when your application shares a single package.json and requirements.txt. No more "the frontend needs TypeScript 5.9, but our library requires 5.5" situations.
Enhanced collaboration: In separate repositories, frontend developers rarely see backend code. When a React developer encounters a slow API call, they can't diagnose the N+1 query problem. In monorepos, the same developer searches the Django views, spots the issue, and submits a fix without switching repositories.
Unified CI/CD: Multirepo architectures mean multiple pipelines with duplicated configuration. Monorepos enable a single pipeline that tests the entire application together, catching integration issues before deployment.
Pinterest's experience illustrates this clearly. By 2021, they managed over 1,365 active repositories, each with its own build system and dependencies. Maintenance became overwhelming. Their solution: migrate to a monorepo structure using Bazel, consolidating into four large monorepos. The result was reduced maintenance burden and faster feature development.
Solving the Django-React integration challenge
The core technical challenge of a Django-React monorepo is asset integration. Development needs hot module replacement (HMR) for instant React updates. Production needs asset files with content-hashed filenames for cache busting. Django templates must reference the correct JavaScript and CSS files regardless of environment.
The Django-React Boilerplate solves this with Webpack and django-webpack-loader, which serves an HTML template with a mount point where React hydrates. Template tags automatically inject the correct Webpack-built bundles.
How it works
Webpack compiles TypeScript and React components into optimized bundles with content-hashed filenames (main.a4f3b2c1.js). During compilation, Webpack generates a webpack-stats.json file containing exact paths of compiled assets:
{
"status": "done",
"chunks": {
"main": [{
"name": "main.a4f3b2c1.js",
"publicPath": "http://localhost:3000/main.a4f3b2c1.js"
}]
}
}
django-webpack-loader, maintained by Vinta, consumes this stats file and injects correct asset references into Django templates:
{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="en">
<head>
{% render_bundle 'main' 'css' %}
</head>
<body>
<div id="root"></div>
{% render_bundle 'main' 'js' %}
</body>
</html>
The render_bundle template tag reads webpack-stats.json and outputs correct <script> and <link> tags. In development, it references the webpack dev server with HMR. In production, it references assets as hashed static files. One template works everywhere.
Configuration in Django:
# settings.py
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'frontend/dist/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
'POLL_INTERVAL': 0.1,
}
}
Type Safety: connecting backend and frontend
API contract mismatches cause frustrating runtime errors. A backend developer adds a field with one name, the frontend expects another, and bugs appear only in production.
The Django-React Boilerplate uses DRF-Spectacular and openapi-ts to generate TypeScript types directly from Django REST Framework views.
The workflow:
- Define your Django REST API with DRF-Spectacular annotations
- Run
python manage.py spectacular --file schema.ymlto generate OpenAPI schema - Run
pnpm run generate:apito create TypeScript types and API client
The generated TypeScript:
// Auto-generated from backend schema
export interface User {
id: number;
email: string;
notificationPreferences: NotificationPreferences;
}
// Type-safe API client
export const apiClient = {
users: {
getProfile: (): Promise<User> => { /* ... */ },
},
};
When you rename Projects to Workspaces in Django, regenerating types immediately shows TypeScript compiler errors in every frontend location that needs updating. The entire refactoring (backend models, API endpoints, TypeScript types, frontend components) happens in one commit with a single atomic deployment.
When to use the Django-React boilerplate
This boilerplate works well when you:
- Need type-safe API contracts that prevent runtime errors (automatic TypeScript generation from Django schemas)
- Are tired of deployment coordination overhead (single atomic deployment, no version mismatches)
- Need full-stack refactoring capability (rename an endpoint across backend and frontend in one commit)
- Value fast onboarding (Docker setup gets new developers running in under 5 minutes)
- Want to catch integration bugs before production (unified CI/CD tests everything together)
Conclusion
The return of monorepos reflects pragmatic choices about development velocity. For web applications with tightly-coupled frontend and backend (the common pattern for startups and product development), monorepos offer substantial advantages. Atomic commits eliminate deployment coordination, unified CI/CD catches integration issues early, and automatic type generation prevents API contract drift.
The Django-React Boilerplate demonstrates how to implement this architecture with production-ready tooling. If you're starting a new Django and React project or facing coordination overhead with separate repositories, check out the Django-React Boilerplate. The README covers everything from initial setup to production deployment, and the included Docker configuration gets new developers running in under 5 minutes.





%201.webp)
