The Ansible best practices documentation recommends to separate inventories:
inventories/
production/
hosts.ini # inventory file for production
The simple option here (and what we do) is simply symlink generic group vars files around.
For instance we might have a generic role for something like NGINX and then a few concrete use cases for that role. In this case we create a group vars file that uses the NGINX role for each concrete use case and then simply symlink those group vars files into the appropriate folders.
Our project folder structure then might look something like this (drastically simplified):
.
├── inventories
│ ├── bar-dev
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── dev.yml -> ../../shared/dev.yml
│ │ └── inventory
│ ├── bar-prod
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── prod.yml -> ../../shared/prod.yml
│ │ └── inventory
│ ├── bar-test
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── test.yml -> ../../shared/test.yml
│ │ └── inventory
│ ├── foo-dev
│ │ ├── group_vars
│ │ │ ├── dev.yml -> ../../shared/dev.yml
│ │ │ └── foo.yml -> ../../shared/foo.yml
│ │ └── inventory
│ ├── foo-prod
│ │ ├── group_vars
│ │ │ ├── foo.yml -> ../../shared/foo.yml
│ │ │ └── prod.yml -> ../../shared/prod.yml
│ │ └── inventory
│ ├── foo-test
│ │ ├── group_vars
│ │ │ ├── foo.yml -> ../../shared/foo.yml
│ │ │ └── test.yml -> ../../shared/test.yml
│ │ └── inventory
│ └── shared
│ ├── bar.yml
│ ├── dev.yml
│ ├── foo.yml
│ ├── prod.yml
│ └── test.yml
└── roles
└── nginx
├── defaults
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
└── main.yml
Now our inventory files can have the hosts use these shared group vars simply by putting the hosts in the correct groups.