Skip to content

Backend

Django Development Company

A framework that has already made most of the boring decisions, so your budget goes on the part of the product that is actually yours.

Overview

Django is a mature, opinionated Python web framework that arrives with almost everything a serious application needs already built: an object-relational mapper, a migration system, a generated administration interface, authentication and permissions, form handling, templating, caching, and a security posture that closes the common web vulnerabilities before you write a line of your own code. The pitch is not that any one of those pieces is the best available in isolation. It is that they were designed together, by people who agreed on how a web application should be shaped, and that coherence is worth more than any individual component.

The way to judge Django is therefore to count decisions rather than features. Every framework choice you do not have to make is a meeting you do not have, a debate that does not divide the team, and a convention the next engineer already knows. How do we handle database migrations? Decided. Where does authentication live? Decided. How do we stop cross-site request forgery? Decided, and switched on. That is the real product. A well-structured Django project reads roughly the same from one app to the next and from one company to the next, which is why handovers work and why hiring is not a lottery.

What you trade away is bespoke architecture. Django has views on how a request should flow, how models relate to the database, and what a project directory looks like, and going against that grain is measurably more painful than going with it. For content-heavy sites, editorial platforms, marketplaces, membership and subscription products, internal operations tools and API back ends that sit in front of Python’s data and machine-learning libraries, that trade is almost always worth making. For a real-time collaborative editor or a high-frequency event processor, it is not, and we will say so before you spend money finding out.

We build and operate Django in production, which means we care most about the properties that only reveal themselves once real traffic and real data arrive. How the ORM behaves when a queryset quietly becomes a hundred queries. What a migration does to a table with tens of millions of rows while users are still on the site. Where the admin stops being a gift and starts being a liability. When the monolith should be split and, far more often, when it should not. This page is our honest working view of a framework we like a great deal and do not recommend universally.

Best for: Data-rich, admin-driven and content-heavy applications: editorial and publishing platforms, marketplaces, booking and membership systems, SaaS back ends, internal operations tools and AI-backed APIs, where a clear relational model, fast delivery and long-term maintainability matter more than bespoke architecture.

Why teams choose Django

  • The boring parts ship on day one

    Authentication, permissions, sessions, migrations, form validation, an administration interface and a hardened security baseline all arrive already built and stress-tested by an enormous number of production deployments. Your first sprint goes to the features that make the product distinctive, not to re-solving problems that every web application in existence shares.

  • Security you inherit rather than bolt on

    Templates escape output by default, the ORM parameterises queries, CSRF protection is on for state-changing requests, passwords use a strong upgradeable hasher, and host validation, secure cookies, HSTS and clickjacking defences are configuration rather than construction. The framework assumes the internet is hostile, which is exactly the posture we want an application to start from rather than reach for after an assessment.

  • The admin is a real operations console

    Django generates a permission-aware CRUD interface directly from your models, with search, filtering and inline editing. For internal tools this is frequently most of the product for almost no effort, and it is customisable enough to become the console a business genuinely runs on. Very few frameworks give you a working back office before you have written a single view.

  • One codebase, one mental model, one hiring pool

    Because Django is opinionated, projects converge on a recognisable shape. That consistency is what makes audits, handovers and onboarding fast, and it is why a Django codebase rarely becomes an unreadable mystery when the original authors move on. You are hiring from a very large pool of engineers who already know the conventions.

  • A straight line into Python’s data and AI stack

    The same process that renders a page can call scikit-learn, run a pandas transformation, query a vector store or invoke a language model, or hand any of it to a background worker. Products that need analytics, scoring or AI features avoid an entire class of integration problems by keeping the web layer in the same language as the intelligence.

Why businesses choose Django

  • The domain is data-shaped, the schema is the spine of the product, and you want the framework to take relational modelling seriously rather than abstracting the database away.
  • Time to market matters and you would rather spend the first month on your business rules than on the plumbing every web application needs.
  • The product handles regulated or personal data, and starting from safe defaults is considerably cheaper than hardening a bespoke stack after an assessment finds the gaps.
  • The roadmap includes reporting, analytics or machine learning, and keeping the web layer in the same language as the data work removes an entire integration seam before it exists.
  • The application will be maintained for years by a changing team, and predictability, documentation and a deep hiring pool matter more to you than architectural novelty.

What we build with Django

The capabilities this technology is genuinely strong at, and what we most often build with it.

  • The ORM and query layer

    Models are Python classes, queries are chainable expressions that compile to parameterised SQL, and relationships are traversed as attributes. The API is expressive enough for the overwhelming majority of application queries, including aggregation, annotation, subqueries, window functions and conditional expressions. It also gives you explicit control when you need it: select_related for joins, prefetch_related for separate lookups, only and defer for column selection, and a clean drop to raw SQL for the query that genuinely outgrows it.

  • Migrations and schema evolution

    Every schema change becomes a numbered, dependency-aware Python file generated from your models, reviewable in version control and runnable forwards and, where sensible, backwards. Data migrations sit alongside structural ones, so a coordinated change across schema and content is one auditable artefact. We treat migrations as first-class code and review them as carefully as anything else, because they are the part of a deploy that cannot simply be rolled back by redeploying.

  • The automatic admin

    A permission-aware CRUD interface generated from your models, with list views, search, filters, inline related editing, bulk actions and an audit trail of changes. Customisation runs from trivial to substantial, and for internal operations tools this is often the fastest route from a data model to something staff can actually use. We invest in it deliberately when it is the operations console and keep it locked down and unglamorous when it is not.

  • Authentication and permissions

    A complete user model with strong password hashing, session management, groups, and both model-level and object-level permissions. Extending or replacing the user model, adding single sign-on or social login, enforcing per-object access and layering multi-factor authentication are all well-trodden paths with mature libraries, rather than research projects with security implications you have to reason about alone.

  • Django REST Framework

    The standard way to build APIs on Django: serialisers that validate and transform data, viewsets that turn a model into a coherent set of endpoints, pluggable authentication, granular permission classes, throttling, pagination, filtering and a browsable API that makes development pleasant. It is what we reach for when a React or Next.js front end, a mobile client or a partner integration needs a clean, versioned JSON contract.

  • Forms and validation

    Django’s form layer handles validation, coercion, error presentation and model binding in one place, which is unfashionable and extremely effective for the workflow-heavy applications the framework suits. Where the front end is server-rendered, this is the difference between a form that mostly works and one that handles every edge case a real user will find in the first week.

  • Caching and the cache framework

    Per-view, per-fragment and low-level caching with a pluggable backend, usually Redis in the systems we build. The point is granularity: caching an expensive fragment or a computed queryset is precise and safe, while a blunt full-page cache tends to be the thing that serves one customer’s data to another. We cache at the level where invalidation is understandable.

  • Background work with Celery

    Anything that should not block a request, sending email, generating exports, calling a slow third-party API, running inference, goes to a task queue with Redis or a broker behind it. This is not strictly part of Django, but it is part of every serious Django deployment we run, and getting retries, idempotency and dead-lettering right at the start is far easier than adding them after an outage.

  • Security defaults and the security team

    Auto-escaping templates, parameterised queries, CSRF tokens, secure cookie and HSTS settings, host-header validation and clickjacking protection, plus a security team that ships timely advisories and patches against a predictable release cadence. For anything handling personal data, that maintained supply chain is as valuable as the code itself.

Use cases

  • Editorial and publishing platforms

    Multi-author content systems, knowledge bases and media sites map naturally onto models, admin and templating. Editorial teams get a usable back office almost immediately, workflow and permissions are explicit, and the content model stays queryable and yours rather than trapped inside a proprietary CMS with an export button nobody trusts.

  • Internal operations consoles

    Back-office tools, case management, fulfilment and line-of-business systems where the admin plus a handful of purpose-built views replaces a sprawl of spreadsheets and manual process. This is some of the highest-return software a business can commission, and Django is unusually well suited to delivering it quickly without it being disposable.

  • Marketplaces, booking and membership products

    Listings, availability, orders, subscriptions, payments and the state machines that connect them. These are relational problems with real business rules and real edge cases, and a framework that takes the schema seriously, enforces constraints and gives you transactional integrity is worth considerably more than a fashionable one.

  • API back ends for modern front ends

    Django REST Framework serving a React or Next.js interface, or a mobile application, with a versioned JSON contract, proper authentication and a rigorous data layer behind it. The front-end team works independently against a stable interface while the domain logic stays in one place rather than leaking into the client.

  • Regulated and data-sensitive back offices

    Applications handling personal, financial or health-adjacent data, where audit trails, granular permissions, encryption, retention rules and a defensible security baseline are requirements rather than aspirations. Starting from a framework whose defaults are already safe materially reduces the work and the risk.

  • AI-backed applications

    Products where the web layer needs to score, classify, retrieve or generate. Because Django is Python, the application can call a model directly for fast paths and hand heavier inference to a Celery worker or a dedicated service, all from one codebase, one deployment story and one language.

When Django is the right choice

  • Right when a relational data model sits at the heart of the product and you want the schema, the queries, the migrations and the operational tooling to live together in one well-understood place rather than scattered across services.
  • Right when the application is content-heavy, admin-heavy or workflow-heavy. Publishing platforms, booking systems, back-office consoles, membership products, anything where a great deal of the value is in structured data being created, reviewed and edited by people rather than in a live interactive canvas.
  • Right when time to market matters and the domain is conventional enough that you want your budget spent on domain logic rather than on rebuilding authentication, admin screens, permissions and form validation for the hundredth time in the industry’s history.
  • Right when the product needs to reach into Python’s ecosystem from the same codebase that serves the requests. Reporting, scoring, forecasting, an embedding pipeline, a call to a language model. No integration seam, no second runtime, no model rewritten in another language and quietly behaving differently.
  • Right when the system will be maintained for years by a team whose composition will change. Django’s conventions, documentation and long-term-support releases make the fifth year cheaper, and the fifth year is where most software actually spends its budget.
  • Wrong for genuinely real-time, highly interactive products. Collaborative editing, live multiplayer, presence-heavy interfaces and streaming-first architectures fight the request-response model. Channels exists and works, but if that behaviour is the core of your product rather than an accent on it, an event-driven stack on Node or Elixir will suit you better and we will tell you so.
  • Wrong when you need a small, fast, single-purpose service. If the job is one endpoint doing inference or a webhook receiver that must start instantly and use minimal memory, FastAPI or a small Go service is a better answer than dragging a full framework along for the ride.

Django: pros and cons

Strengths

  • Enormous productivity from strong conventions. The ORM, migrations and admin together can save weeks on any data-driven product, and the savings recur every time you add a model.
  • Secure by default in a way few frameworks match. Injection, cross-site scripting, CSRF and clickjacking are addressed by the framework rather than by your discipline.
  • A migration system that is genuinely good. Schema changes are generated from model changes, version-controlled, dependency-aware and reviewable in a pull request like any other code.
  • Predictable long-term-support releases and a security team with a clear disclosure process, which matters a great deal for anything handling real user data.
  • A vast, stable ecosystem of mature third-party apps, and Django REST Framework as a de facto standard for building serious APIs on top.
  • Excellent documentation. Django’s docs are among the best in any framework, and that quietly reduces the cost of every unfamiliar problem your team meets.

Trade-offs

  • The ORM is a leaky abstraction and its footguns are real. It makes N plus one query patterns effortless to write and invisible to read: a template loop over related objects can turn one query into hundreds without anything in the code looking wrong. select_related, prefetch_related, only and defer fix it, but you have to know to look, and the fix is a habit rather than a setting.
  • Unbounded querysets are the other recurring failure. Code that works beautifully on a table of ten thousand rows will attempt to load ten million into memory two years later, and the first symptom is usually a worker being killed rather than a helpful error.
  • Monolith gravity is real. Django makes it so convenient to add another app to the same project that boundaries blur unless somebody actively defends them, and by the time you want to extract a service, half the codebase imports models from the other half. Splitting later takes deliberate architectural effort, and it never comes free.
  • Migrations on large tables are an operational event, not a deployment detail. Adding an index or rewriting a column can lock a busy table for a long time, and Django will happily generate a migration that does exactly that. Zero-downtime schema change on a large database requires you to know what Postgres does under the hood, which the framework will not teach you.
  • The async story is partial and easy to get wrong. Django supports async views and ASGI, but the ecosystem around it, the ORM in particular, is only partly async, and mixing the two models carelessly produces subtle blocking that is genuinely hard to diagnose. If your workload is fundamentally async and high-concurrency, FastAPI is the more honest starting point.
  • Server-rendered templates suit content and forms far better than rich interactive interfaces. Once the front end needs real client-side state, you end up running a JavaScript application alongside Django anyway, and then you are maintaining two things and a contract between them.
  • Opinionated by design. When your requirements genuinely differ from Django’s assumptions, about the user model, about multi-tenancy, about how requests should flow, you are working against a strong current, and the cost of that fight compounds across the life of the project.
  • The admin is not a customer-facing product. It is a superb internal tool and a poor end-user experience, and every project that tried to ship it to customers as the real interface has regretted it. Treat it as scaffolding for your staff, not as your UI.

How we structure a Django application

We lay projects out as a set of focused apps with defended boundaries, each owning its models, its views and its migrations, rather than one sprawling module that accumulates everything. Business logic lives in explicit service functions and model methods, kept firmly out of views and templates, so the interesting decisions are unit-testable without an HTTP request and reusable from a management command, a Celery task or a test. Views stay thin: parse, authorise, delegate, respond. This is not architectural purity for its own sake. It is the single discipline that determines whether the project is still pleasant to work in at year three.

Cross-app imports are where monolith gravity does its damage, so we watch them deliberately. An app that imports another app’s models freely has quietly merged with it, and the merge only becomes visible when somebody tries to extract a service. We prefer explicit interfaces between apps, keep foreign keys where they genuinely reflect the domain, and accept a little duplication rather than a lot of coupling. If a service boundary is eventually warranted, this is what makes it a project rather than a rewrite.

Configuration is environment-driven with settings split so local, staging and production differ only where they must, and secrets come from a managed store rather than the repository. The application ships as a container image built in CI so that what we tested is what runs. Static and media assets go to object storage behind a CDN rather than through the application, read-heavy paths are cached at a granularity where invalidation is comprehensible, and anything that should not block a request goes to Celery from the very first version rather than being retrofitted after the first timeout.

The database deserves architectural attention rather than being treated as a detail the ORM handles. We choose PostgreSQL by default and use it properly: real constraints and unique indexes so the database enforces invariants the application might forget, deliberate index design, transactions scoped tightly around the work that must be atomic, and connection pooling in front of it because a fleet of workers will exhaust a Postgres connection limit long before it exhausts the machine. The ORM is a convenience layer over a database you still need to understand.

Performance in practice

Django’s own request overhead is rarely the bottleneck for the products it suits. The database and the shape of your queries are, and the overwhelming majority of Django performance problems we are asked to diagnose fall into three families: N plus one query patterns, missing or wrong indexes, and querysets with no bound on how much they will load. All three are things the ORM makes easy to create and slightly harder to notice, which is precisely why they are so common and why they are so satisfying to fix.

The N plus one problem deserves particular attention because it hides in templates. A loop that renders a related field looks like presentation code and behaves like a query generator, and because each individual query is fast, nothing in your monitoring screams. The fix is select_related for forward relations, prefetch_related for reverse and many-to-many, and, more importantly, the habit of looking at query counts per request rather than only at total response time. We instrument that from the beginning, so a regression shows up as a number going up rather than as a page that feels sluggish.

Beyond the query layer we cache at the right granularity, per-fragment or per-queryset in Redis rather than a blunt full-page cache that will eventually serve the wrong user the wrong data. We run Django under a properly configured WSGI or ASGI server with worker counts sized against measured behaviour rather than a default. Slow work goes to background tasks. Where a specific query genuinely outgrows the ORM, an intricate analytical aggregation or a hot path that needs a hand-tuned plan, we drop to raw SQL for that path alone and leave the rest of the codebase readable.

We are also honest about the ceiling. Django is fast enough for content, workflow and admin-driven products by a comfortable margin. It is not the tool for tens of thousands of tiny requests per second per node, or for latency budgets measured in single-digit milliseconds. If that is your workload, the right answer is a different runtime for that component, not a heroic tuning effort against a framework that was never aiming at it.

Security as a starting position

Django is one of the few frameworks where the secure choice is also the default choice, and that matters more than any individual feature. Templates escape output unless you explicitly mark it safe. The ORM parameterises queries, so string-built SQL injection is simply not on the table for normal application code. CSRF protection is on for state-changing requests. Passwords use a strong, upgradeable hasher rather than something a developer invented. Secure cookies, HSTS, host-header validation and clickjacking protection are a settings change we apply as standard rather than a project.

We treat those defaults as the floor. On top of them we add authorisation checked at the object level rather than inferred from a URL, which is the single most common real vulnerability we find in inherited Django applications: a view that confirms you are logged in and never confirms the record belongs to you. Then rate limiting on authentication and other sensitive endpoints, careful handling of file uploads, signed and expiring URLs for private media, and audit logging on the actions that would matter in a dispute.

The admin gets specific attention because it is a concentrated privilege surface. It should not sit at a guessable path on the public internet without additional protection, staff accounts should have multi-factor authentication, and permissions should be granted per role rather than by handing out superuser status because it is quicker. An otherwise well-built application with a loosely protected admin is one credential away from a very bad day, and we have seen exactly that inherited more than once.

Finally, the supply chain and the data. Dependencies are pinned, locked and scanned in CI, and Django’s own security releases are applied promptly rather than accumulating until an upgrade becomes frightening. For personal data we design retention and deletion as features rather than intentions, keep sensitive fields encrypted where the threat model justifies it, ensure database backups are encrypted and access-controlled, and make sure error reports and logs do not quietly become an unprotected copy of the information you are obliged to look after.

Scaling a Django system

Django scales the way most well-built web applications scale: horizontally at the application tier, and with considerably more care at the data tier. A typical Django process is stateless, so adding capacity means running more workers behind a load balancer, which is straightforward and boring in the best sense. Sessions go to Redis or the database rather than local memory, uploads go to object storage rather than local disk, and nothing important lives on a particular machine. Get that right at the start and scaling the application tier is a configuration change.

The pressure then lands squarely on PostgreSQL, and that is where the real engineering is. Connection pooling comes first, because a growing fleet of workers will hit the connection limit long before it saturates the hardware, and PgBouncer in front of Postgres solves a problem that a larger instance does not. After that: indexing driven by actual query plans rather than intuition, read replicas for read-heavy reporting so analytics never competes with the transactional path, and partitioning where the data model genuinely calls for it. Most Django scaling work is database work wearing a framework’s clothes.

Schema change at scale is its own discipline and one that catches teams unprepared. On a large, busy table, adding a column with a default, creating an index without the concurrent option or changing a column type can take a long lock and effectively take the site down. Django will generate those migrations without complaint. We plan them as operations: concurrent index creation, additive changes deployed in stages, backfills run in batches through a background job, and the removal of the old column as a separate later deploy once nothing reads it. It is more steps and it does not require an outage window.

On the architectural question, we are deliberately conservative. Django leans monolithic, and for most teams that is a strength rather than a limitation: one deployable, one mental model, one place to look. Fragmenting into services before the scale or the organisational structure justifies it buys you distributed transactions, network failure modes and a deployment matrix in exchange for tidiness. When a genuine boundary emerges, a component with a different scaling profile, a team that needs to deploy independently, we extract it consciously with a clear contract, and we will tell you when we think the split would cost more than it saves.

Django integrations & ecosystem

The technologies we most often pair with it. Each links to how we work with it.

How we deliver

We start with the data model, because in a Django project the schema is the product’s spine and everything else is built on top of it. We map the domain into models, relationships and constraints, argue about the awkward parts early, and get a working admin in front of stakeholders within the first week or two so the shape of the data can be interrogated by the people who understand the business before features pile on top of it. Correcting a model in week two is a conversation. Correcting it in month six is a migration, a backfill and a set of code changes across the codebase.

From there we build in thin vertical slices: one real user journey, end to end, behind tests, then the next. We do not assemble layers that only meet at the end, because that is how integration risk gets deferred to the point where it can no longer be absorbed. Each slice is demonstrable and, in principle, releasable, which keeps the conversation about priorities honest rather than theoretical.

Every project runs in CI from the first week: tests, linting, type checking where it earns its place, dependency and security scanning, and a container build that mirrors production. Migrations are reviewed as carefully as application code, and any migration that touches a large table is discussed as an operation before it is merged. Because we operate what we build, logging, error tracking and query-count monitoring are wired up before launch rather than after the first incident teaches us we needed them.

Senior engineers stay on the work throughout. There is no handover from the people who designed the system to juniors who implement it, which is the point at which most consultancy engagements quietly lose their quality. The person who modelled your data is the person accountable for how it behaves in production, and that accountability is what makes the architectural decisions careful in the first place.

The service behind it

Delivered throughCustom Software Development

What we build with Django

The disciplines this technology most often shows up in, from a first build to taking over and stabilising an existing one.

How we deliver

  1. 01

    Discover

    We map the system, the constraints and the business it serves, including the parts nobody documented.

    Architecture brief

  2. 02

    Architect

    Decisions get made, written down and defended before a line of production code exists.

    Decision records

  3. 03

    Build

    Short cycles against working software. You see progress in the product, not in a status deck.

    Shipping increments

  4. 04

    Operate

    Monitoring, incident response and iteration. The system is alive, so the engagement is too.

    Runbooks & SLOs

Weighing up Django?

A short call with engineers who build in it and operate the result. If Django is the wrong tool for what you are doing, we would rather tell you now than bill you later.

Industries we use Django in

Domain knowledge changes what gets built. A few of the sectors we know before the first meeting.

Also in Backend

Why teams choose us for Django

  • We operate what we build

    We run Django applications in production ourselves, so we design for the slow query, the awkward migration and the three in the morning incident rather than the demo. That perspective shapes the architecture from the first week, because the decisions that make a system operable are made long before it is operated.

  • Senior engineers, start to finish

    Your project is delivered by people who have shipped and maintained Django systems for years, not staffed out to juniors once the engagement is signed. The person modelling your data is the person accountable for how it behaves under load.

  • We know where the ORM bites

    N plus one patterns, unbounded querysets, migrations that lock a large table, an admin that becomes unusable at scale, and cross-app coupling that quietly welds a monolith together. These are the things that make a Django project expensive in year three, and we design against every one of them from the start.

  • Honest about trade-offs

    If Django is the wrong tool for your problem, a real-time collaborative product, a tiny high-throughput service, a mobile-first application with no meaningful back office, we will tell you before you spend money finding out. We recommend the framework when it fits, and something else when it does not.

Typical timeline

  1. 01

    Discovery

    One to two weeks. Domain and data modelling, architecture, security and integration review, and a costed plan with the genuine risks named rather than smoothed over.

  2. 02

    Foundation

    One to two weeks. Project structure, core models and migrations, authentication and permissions, a working admin in front of stakeholders, and the CI and deployment pipeline running end to end.

  3. 03

    Build

    Iterative cycles delivering vertical slices of real functionality, each tested, reviewed and demonstrable. Priorities are revisited every cycle against what the previous one taught us.

  4. 04

    Hardening and launch

    One to two weeks. Query profiling and index review, security review including the admin surface, load testing against production-shaped data, observability, and a controlled release with a rollback plan that has actually been tried.

  5. 05

    Operate

    Ongoing. Monitoring, patching, Django and dependency upgrades on the LTS cadence, performance work as data grows, and continued iteration on the live system.

How pricing works

  • A paid discovery engagement first, typically one to two weeks. Domain and data modelling, architecture decisions, security and integration review, and a costed delivery plan that you own and could take to another firm. Charging for it is deliberate: the thinking is the valuable part, and an estimate produced without it is a guess dressed up as a number.
  • Fixed-scope pricing where the requirements are genuinely clear. A defined application, a migration, an integration or a specific set of features with agreed acceptance criteria. Where we can carry the estimation risk fairly, we will.
  • A monthly senior engagement for continuing build work, with scope reviewed each cycle so spend and direction stay visible and adjustable rather than committed a year ahead. You see what was delivered each month, and you can stop.
  • An operate-and-improve arrangement for live products: monitoring, security patching, Django and dependency upgrades, performance work and iterative feature delivery. Django’s long-term-support cadence makes this predictable, and staying current is far cheaper than a rescue upgrade three versions later.
  • Third-party costs, cloud hosting, managed databases, email and payment providers, commercial licences, are billed to your own accounts at cost with no mark-up from us. The contracts and credentials stay yours, which is also what makes leaving us straightforward if you ever want to.

Hire Django engineers

Need Django capacity on your own team? We embed named senior engineers into your existing team (reporting to your leads, working in your rituals), so you add capacity without a hiring cycle.

Hire Django engineers

Common questions

Is Django a sensible choice for an API rather than a website?

Yes, and Django REST Framework is one of the strongest reasons to pick Django at all. You get serialisation, validation, authentication, granular permissions, throttling and pagination as first-class tools, backed by a rigorous data layer and a migration system. It is an excellent choice when you want a JSON API in front of a relational model that will be consumed by a React or Next.js front end or a mobile client. The counter-case is a small, single-purpose, high-concurrency service, where FastAPI gives you less framework and a more natural async model.

Where does the ORM stop being your friend?

In three places. First, complex analytical queries: window functions, recursive queries and intricate aggregations are expressible but often clearer and faster written directly in SQL. Second, hot paths where you need to control the exact query plan and the ORM keeps producing something reasonable but not optimal. Third, and most commonly, when nobody is watching query counts and a template loop quietly turns one request into hundreds of queries. The first two are handled by dropping to raw SQL for those specific paths, which Django supports cleanly. The third is handled by instrumenting query counts per request from the beginning so a regression is a number rather than a feeling.

How do you run a migration on a large table without downtime?

Carefully, and in more steps than the auto-generated migration suggests. Django will happily produce a migration that takes a long exclusive lock on a table with tens of millions of rows, and on a busy site that is an outage. We use concurrent index creation, make schema changes additive first so old and new code can both run, backfill data in batches through a background job rather than inside the migration, deploy the code that uses the new shape, and only then remove the old column in a later migration. Every step is reversible and none of them require a maintenance window. This planning is exactly the kind of thing that separates a deploy from an incident.

Can we give the Django admin to our customers?

We would strongly advise against it. The admin is superb as an internal operations console for trained staff, and it is a poor product experience for customers: the interaction model assumes you understand the data model, the permission granularity is per-model rather than per-workflow, and it exposes a great deal of structure you probably do not want to explain. Every project we have seen try this has ended up rebuilding the customer-facing part properly. Use the admin for your team, build a purpose-designed interface for your users, and get the benefit of both.

Is Django async, and does that matter for us?

Partly, and it depends. Django supports ASGI and async views, and that is genuinely useful for endpoints that mostly wait on external services. But the ecosystem is only partly async, the ORM in particular, and mixing async views with synchronous ORM calls carelessly produces blocking that is difficult to spot and unpleasant to debug. Our practical position is this: if async concurrency is an accent on an otherwise conventional application, Django handles it fine with care. If high-concurrency async is the fundamental shape of your workload, FastAPI is the more honest starting point and we will say so rather than talk you into the framework we happen to be discussing.

Django is a monolith. Should we be building microservices instead?

Almost certainly not yet, and possibly not ever. The monolithic default is a genuine strength for small and mid-sized teams: one deployable, one mental model, one place to look when something is wrong, and transactions that actually work because everything shares a database. Splitting into services buys you independent deployment and independent scaling, and it costs you distributed failure modes, data consistency problems, a deployment matrix and a great deal of operational overhead. That trade pays off when your organisation genuinely needs teams to deploy independently, or when one component has a wildly different scaling profile. We design clean app boundaries from the start so the option stays open, and we recommend taking it only when it clearly pays for itself.

How does Django fit with AI and machine-learning work?

Naturally, because Django is Python. Your application can call scikit-learn or a scoring model directly for fast paths, run a retrieval pipeline against a vector store, or invoke a language model, all from the same codebase and the same deployment. Anything slow or expensive goes to a Celery worker so it never blocks a request. This removes the integration seam you would otherwise carry between a non-Python web layer and Python model logic, which in practice is where a lot of subtle production bugs live: two implementations of the same feature computation that were meant to agree and eventually do not.

Can you take over an existing Django project?

Yes, and a good deal of our work is exactly that. We start by reading it and instrumenting it rather than by proposing a rewrite: query counts, slow endpoints, the dependency and Django version position, the state of the migrations, and the security posture of the admin and the permission checks. Then we make change safe before we make it fast, adding tests around the risky parts, before working through the upgrade path and the structural problems in order of what is actually costing you. Big-bang rewrites of working software are usually the most expensive available option, and we will argue against one unless the evidence is genuinely overwhelming.

Building on Django?

Tell us what you are building and where it is stuck. A senior engineer reads it and gives you an honest read on whether Django is the right fit for the problem, or what we would reach for instead.

  1. 01A senior engineer reads it. Not a form queue, and not an account manager.
  2. 02We reply either with questions or with a straight answer that we are not the right fit.
  3. 03If it looks like a fit, a technical call with the person who would actually run the delivery.
  4. 04Then scope, effort and risk in writing, before anyone signs anything.

Two fields required. We reply to real enquiries. No list, no sequence.