Model or dataset
Django-CRM/Django-CRM avatar
Django-CRM/Django-CRM

BottleCRM: a Django and SvelteKit CRM that isolates tenants in PostgreSQL

Open Source CRM for Startups and enterprises. Django + SvelteKit · Self-hosted · Multi-tenant · Free forever

2,419 stars1,050 forksPythonMIT

At a glance

What is it?
BottleCRM is an MIT-licensed, self-hosted CRM built on Django REST Framework, SvelteKit and Flutter, with PostgreSQL Row-Level Security as its tenant boundary. The interesting engineering decision is where that boundary sits, and it is also the reason the project is not for everyone.
Who is it for?
Adopt BottleCRM if you want a Django codebase you can extend, you are willing to run PostgreSQL and object storage yourself, and you either need database-level tenant isolation or do not mind carrying it for a single organisation. Do not adopt it if you want a vendor to hold the pager, or if your team has no Python capacity, because the escape hatch from every gap is a Django change.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem BottleCRM targets, and the two audiences it splits between

Two different buyers read the same README. The first is a company that wants its customer records in its own PostgreSQL instance rather than a vendor's cloud, and is prepared to run that instance. The second is a small SaaS operator who wants to sell CRM seats without building a CRM, and therefore needs several organisations to share one deployment without seeing each other's rows. BottleCRM addresses both with the same codebase, and that is the source of most of its design decisions.

The feature surface named in the README covers leads, accounts, contacts, opportunities, support tickets, tasks and invoices. The repository topics add CPQ, helpdesk, invoicing and lead management. The helpdesk is described as having SLA timers, approvals, escalations, macros and a knowledge base, which is a different level of commitment from a ticket list bolted onto a contacts table. Pricing is the other half of the pitch: the README states unlimited users and records with no subscription, and the comparison table claims free unlimited users against per-seat SaaS pricing. That is a licensing and hosting claim rather than a performance claim, and it is the one most readers will actually be shopping on.

Where the tenant boundary actually sits

The mechanism the README leads with is PostgreSQL Row-Level Security. Tenant isolation is enforced in the database rather than in Django querysets or view decorators. The practical consequence is that a missing filter in a view does not by itself leak another organisation's rows, because the database refuses them. That is a meaningfully stronger position than application-level filtering, where one forgotten .filter(org=...) is a breach.

It is also a constraint, and the README does not pretend otherwise. RLS means PostgreSQL is not optional. The self-hosting documentation linked from the README has a page on PostgreSQL and Row-Level Security, which suggests the project treats the database configuration as a first-class deployment concern rather than an implementation detail. Anything that connects to the database outside the application's expected path, a reporting tool, a migration script, a psql session, has to be aware of the policy in force. Readers who want to run this on SQLite for a quick look should treat that as unsupported in spirit even if the code allows it.

Above the database, one Django REST Framework backend serves three clients: a Svelte 5 web application, a Flutter app for iOS and Android, and the documented REST API. The README states that an OpenAPI schema ships with the repository, which is what lets an agent discover endpoints rather than being handed a hand-written tool list. Authentication for that path is a personal access token, and the README says the token inherits the caller's role, organisation and permissions. That matters: an agent acting through a token is bounded by the same RLS policy as the human who issued it, not by a separate service account with broader reach.

Getting a local instance up, and what the quick start leaves out

The README gives a three-command quick start:

git clone https://github.com/django-crm/Django-CRM.git cd Django-CRM docker compose up --build

After that, the frontend is at http://localhost:5173 and the API with Swagger UI at http://localhost:8000/swagger-ui/. The README explicitly defers the rest to docs/getting-started/docker-quick-start.md, which it says covers the default admin login, loading demo data, and what each service does. That deferral is honest and also a warning: the quick start does not tell you the credentials, so you cannot log in from the README alone. Plan to read that file before you start the build, not after.

The stack versions are pinned in the README badges: Python 3.12 or newer, Django 6.x, Django REST Framework, SvelteKit 2.x, Svelte 5, Flutter 3.44 or newer. A coverage badge is referenced from the repository. The README also points to docs/self-hosting/requirements.md for production deployment, PostgreSQL and Row-Level Security, backups and security hardening. There is a manual setup path as well as Docker, according to the getting-started description. For anything beyond a laptop, the self-hosting section is the document that matters, and it is linked rather than summarised, so you will be reading it in the repository.

The self-hosting bill nobody puts on the pricing page

Free is a licence statement, not a total cost. Running BottleCRM means running PostgreSQL, the Django application, the SvelteKit frontend, and whatever serves the Flutter app's backend traffic, plus backups and the security hardening the self-hosting docs describe. The README mentions managed hosting as an option in its comparison table, so there is a commercial path, but the default posture is that you operate it.

Upgrade cost is visible in the release cadence. v1.9.0 and v1.9.1 landed on the same day in August 2026, and v1.9.2 followed on 5 September 2026. Three releases in roughly three weeks on a 1.9.x line suggests active iteration. For an operator that means either tracking releases closely or pinning and accepting drift, and the choice interacts with the database: schema migrations against a PostgreSQL instance with RLS policies are not a rollback-friendly operation. The self-hosting documentation lists backups as a topic, which is the right place to start reading before your first production migration.

The licence is MIT, per the README and the LICENSE file. That is permissive: forking, modifying and redistributing are permitted, and there is no copyleft obligation to publish your changes. It also means no warranty and no obligation on the maintainers to fix anything. Commercial support is offered through MicroPyramid, the sponsor named in the README. This is a description of the licence, not legal advice; check the LICENSE file and your own counsel for anything that matters.

What the README does not tell you

There is no performance data here. No throughput figures, no record-count limits, no latency numbers, and no statement about how RLS policies behave as tenant count grows. If you are evaluating BottleCRM for hundreds of tenants, that is an open question you will have to answer yourself, on your own hardware, with your own data shape. The README's comparison table asserts database-level multi-tenancy as an advantage over typical open source CRMs; it does not quantify the cost of that choice.

There is also no migration tooling described in the repository material. The README links to a migration page on the marketing site for moving from Salesforce or HubSpot, but the technical documentation index lists getting started, self-hosting, API reference and contributing. Nothing in the supplied material describes an importer, a CSV mapping format, or a schema translation step. Treat migration as an unsolved problem until you find documentation for it.

The Flutter app is named and versioned but not documented in the README beyond its existence and platform coverage. Whether it supports the full feature set or a subset is not stated. If mobile is a requirement rather than a nice-to-have, verify that before you commit.

BottleCRM against a general-purpose Django admin, and against SaaS

The nearest real alternative for a Python team is not another CRM. It is Django admin plus django-rest-framework, with a small set of models for accounts, contacts and deals. That approach shares the same stack and the same hosting burden, and it gives you total control over the schema. The difference is everything above the models. BottleCRM ships the helpdesk with SLA timers, approvals, escalations and macros, the invoicing and CPQ surface, the SvelteKit frontend, the Flutter app, the OpenAPI schema and the RLS policy layer. Rebuilding those is months of work, and the RLS layer in particular is the part teams underestimate. If your CRM needs are genuinely a contacts table and a pipeline view, Django admin is cheaper and you should not adopt BottleCRM. If you need the helpdesk and invoicing surface, the comparison stops being close.

The other alternative is a SaaS CRM. The README's own table frames the trade: per-seat pricing and vendor-controlled data on one side, self-hosting and total data ownership on the other. The honest version of that trade is not about cost at small scale, where a SaaS seat is cheap. It is about what happens when you need a field the vendor will not add, or an export the vendor will not give you. With BottleCRM the answer is a Django migration you write yourself. With SaaS the answer is a support ticket. Pick the one whose failure mode you can live with.

Who should adopt BottleCRM, and the first two things to check

Adopt it if your team writes Python and wants the CRM to be a codebase rather than a subscription. The README's claim that Django 6 and Svelte 5 mean your team can extend it on day one is plausible on its face: these are mainstream frameworks with large bodies of existing documentation, not a bespoke in-house stack. Adopt it also if multi-tenancy at the database layer is a requirement you can articulate, because that is the feature that is hardest to retrofit onto an existing open source CRM later.

Do not adopt it if nobody on your team will own a PostgreSQL instance, its backups, and its upgrade path. Do not adopt it if you need a vendor to hold the pager, or if your organisation cannot run a Django deployment at all, because every gap you find resolves to a Python change. And do not adopt it on the strength of the quick start alone: three commands get you a laptop instance with no credentials in the README, which is a demo, not a deployment.

Two checks before you commit. First, read docs/self-hosting/requirements.md and confirm the topology it describes is one you can operate, including the backup arrangement. Second, run the docker compose stack, open http://localhost:8000/swagger-ui/, and confirm the endpoints you actually need are documented there rather than only described in the marketing feature list. If both pass, the remaining question is whether you want to own a CRM or rent one.

Editorial conclusion

Adopt BottleCRM if you want a Django codebase you can extend, you are willing to run PostgreSQL and object storage yourself, and you either need database-level tenant isolation or do not mind carrying it for a single organisation. Do not adopt it if you want a vendor to hold the pager, or if your team has no Python capacity, because the escape hatch from every gap is a Django change. Before committing, verify two things: that the default docker compose stack is not what you plan to expose to the internet, and that the docs/self-hosting/requirements.md page describes a topology you can actually operate.

Official sources

  1. Django-CRM/Django-CRM on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes