Code Agency
4 min read

Vetting OCA modules: how we decide what community code touches production

The OCA ecosystem is Odoo's superpower and its minefield in equal measure. The checklist we run — maintainer activity, test coverage, migration history — before a community module ever reaches a client's production database.

Ask any long-time Odoo shop about OCA and you'll get two answers in the same breath: it's the reason custom-development budgets stay sane, and it's the reason some clients call mid-quarter about a production bug nobody in the room wrote. Both are true, and they're not in tension — they're the same fact seen from before and after someone skipped a review.

We run OCA code on nearly every Odoo implementation we deliver, usually more of it than the project plan advertises, because the good modules are invisible: queue_job quietly handling async work, the server-tools Sentry hook we've written about before, a handful of localisation and reporting addons nobody asks about because they just work. That track record is precisely why the modules that don't get vetted are dangerous — the ecosystem's average quality is high enough to make people stop checking.

Before anything from OCA reaches a client database, it passes a checklist. Here's what's on it.

Maintenance activity

A module's last commit date tells you more than its star count. We check:

  • Commits in the last 12 months — not necessarily features, but responses to Odoo point releases and reported issues.
  • Who's committing. A module maintained by one contributor from a single company is a bus-factor risk; one with commits from three or four unrelated GitHub handles has survived turnover already.
  • Open issue age. A tracker with two-year-old bug reports and no maintainer replies is a module we route around, however well it demos.

The OCA org itself tracks a chunk of this via each repository's maintainer-quality badges — CI status, code coverage, translation completion — and we treat a missing or red badge as a question to answer, not a reason to reject on sight.

Test coverage

Check before you trust it
# does the module ship tests at all?
find . -path "*/tests/test_*.py" | wc -l
 
# does CI actually run them for the target Odoo version?
grep -A2 "odoo-version" .github/workflows/*.yml 2>/dev/null

No tests doesn't automatically disqualify a module — some genuinely small addons (a report layout, a menu reorganisation) don't need much. But anything that touches stock valuation, accounting entries, or access rules gets read line by line if the test suite doesn't already prove the behaviour we're relying on. We've caught rounding bugs in community accounting modules this way, the kind that only surface at year-end close.

Migration history

OCA modules live and die by whether they survive an Odoo major version bump. We look at the module's commit log across at least two previous version branches (17.0, 18.0, 19.0) and ask:

  1. Did the migration happen at all, or did the module quietly drop off the org at some version?
  2. How long after the Odoo release did the migrated branch land? Same week is a healthy sign; eighteen months is a module we'll be migrating ourselves.
  3. Did the data model change in ways that need a migration script, and does one exist?

This matters more than almost anything else on the list, because it's the direct input to our own upgrade planning. A module with a two-version migration gap becomes our team's problem the day a client wants to move off an EOL Odoo release — better to know that on day one than discover it mid-upgrade.

Dependency footprint and license

Some OCA modules pull in half a dozen sibling modules from the same repository, each with its own maintenance profile — the checklist above has to run recursively, not just on the module you actually wanted. We also confirm the license (OCA repositories are consistently LGPL-3 or AGPL-3, but individual modules occasionally vendor code under stricter terms) and flag anything that would constrain how we distribute a client's customisations later.

The decision, in practice

Every module that passes gets logged in the project's fit-gap analysis alongside the custom development it replaces — the whole point of fit-gap is comparing real costs, and "adopt this OCA module" is a cost line just like "build it ourselves," with maintenance risk instead of a line-item invoice. Every module that fails becomes one of three things: a custom module we write with tests from day one, a fork we maintain ourselves with the upstream commit history kept intact, or a feature request we open against the original repository, because sometimes the fix is faster than the workaround.

The checklist takes an afternoon per module the first time a client's stack needs one. It's the difference between an OCA install being the reason your Odoo implementation is faster to build and cheaper to run, and being the incident nobody signed up for.

Want us to publish something specific?

Tell us what you'd like to read and we'll add it to our writing queue.

Get the next one in your inbox

New articles, videos and the occasional engineering note — a short mail when there’s something worth reading, nothing else.