All you need to know about db filtering in Odoo

In Odoo

First have a look at the official deployment documentation, which has a good introduction paragraph about db filtering.

Odoo is a multi-tenant system: a single Odoo system may run and serve a number of database instances.


Let's take some examples to illustrate how does the code works:

dbfilter is a regex that is built dynamically: you can use variables %d and %h to adapt its content depending on the HOST header of the http request.


So, if you define dbfilter = ^%d.*\Z, a user accessing will have access to databases matching ^demo.*\Z, e.g.:

  • demo
  • demo_backup_20180404


re.match is used: dbs = [i for i in dbs if re.match(r, i)]

So it's easy to write a regex more permissive than expected. If you define dbfilter = demo_* for example, it will also match demoinefromage_prod.

dbfilter_from_header module

You can't always match databases names with domain names.

For example, you might have a single Odoo instance to serve 2 databases:

  • customer1_prod
  • customer2_prod

But each of these customers wants its own custom domain, respectively:


To support this case, you can use OCA's dbfilter_from_header module.


$ git clone -b 9.0 --no-checkout --single-branch --depth 1
$ cd server-tools
$ git config core.sparsecheckout true
$ echo "dbfilter_from_header" > .git/info/sparse-checkout
$ git read-tree -mu HEAD


On Nginx side, you need to define a dedicated dbfilter for each virtual host.

In our case, for



location / {


    proxy_set_header X-Odoo-dbfilter ^customer1_.*\Z;

2 things to note:

  • before passing the request to Odoo, Nginx takes all HTTP headers, lowercase them and converts dashes to underscores;
  • we use \Z instead of $ to match end of string, because nginx cannot escape $

2 levels of filtering

dbfilter_from_header respects the dbfilter defined at Odoo level, so we can setup 2 levels of filtering:

  • dbfilter = ^.+prod.*$
  • proxy_set_header X-Odoo-dbfilter ^.*customer1.*\Z;