There is no single "best". It depends on your requirements, what software you use, what the capabilities of your existing software are, etc.
I use Eagle to design boards, and long ago created my own system around Eagle for generating BOMs. Cadsoft later brought out some ULPs and the like for the same purpose but that work differently. Since mine work, and quite nicely at that, I continue to use my existing software.
In Eagle, I use attributes on parts for defining things like manufacturers, their part number, suppliers, their part numbers, values, description string for the BOM, etc. This by itself works fine except for dealing with in-house part numbers for multiple different customers.
To do that, I have a series of CSV files stored in a place known to the BOM software. These files relate the part information in Eagle to in-house part numbers. The entries can also be set up to use the same stocked part for different purposes, and then group the result on a single BOM line.
Here is the header line common to these CSV files:
Desc,Value,Package,Subst,Inhouse Acme,Manuf,Manuf part #,Supplier,Supp part #
Note the "Inhouse Acme" field. This sample file is for the Acme customer, and that field gives the in-house part number for Acme. I keep one CSV file per customer.
Each directory in a tree where I keep Eagle files can have a "housename" file. The lowest down the tree to a particular leaf node of such files provides the house name. This is how my system automatically handles multiple customers, each with their own part numbering scheme.
The BOM software has the data specified for each part in Eagle, and looks for matches in this file. Matches can be by value or definitive. For example, if two parts have the same manufacturer and manufacturer part number, then they are the same part definitively. Otherwise, if the description, value, and package match, then the part matches by value.
Here is a snippet of such a file:
These are a bunch of 0805 capacitors that only differ in capacitance. The capacitance value is added to the base part in the schematic, and has to be entered the same as here for it to match. If a match is found to any of the above, the in-house part number is known. For example, such a cap given a value of "1nF" in the schematic will pick up in-house part number 9133058.
Another useful thing my software does is collapse all uses of the same in-house part. Here is another snippet from the Acme file:
"Capacitor, unpolarized",1uF 10V,SMD-0805,Yes,9133054,,,,
"Capacitor, unpolarized",1uF 25V,SMD-0805,Yes,9133054,,,,
"Capacitor, unpolarized",1uF 35V,SMD-0805,Yes,9133054,,,,
"Capacitor, unpolarized",1uF 50V,SMD-0805,Yes,9133054,,,,
"Capacitor, ceramic",1uF 50V 10% -55+100C,SMD-0805,Yes,9133054,,,,
Note that these are all 1 µF 50 V capacitors in 0805 surface mount package. Acme has decided to only stock 50 V parts, then use those even when lower voltage parts would do. That's a very legitimate stocking strategy, especially for cheap parts like these.
However, I still want to show on the schematic that only a 10 V part is needed. In that case, the 10 V part description matches the first line, and part number 9133054 is assigned. Since the next line has the same in-house part number, it matches that line too, and the description is updated to "1uF 25V". This continues until it gets to the bottom line shown, where the description is updated to "1uF 50V 10% -55+100C". That's what ends up on the BOM for any of the capacitors listed. The schematic might show a "1uF 10V" cap in one place and a "1uF 35V" cap in another, but they both get lumped on the same BOM line as "1uF 50V 10% -55+100C" for this customer only.
If Acme ever decides to stock 1 µF 35 V parts, this section of the file would be updated. When the BOM is re-run, the 10-35 V parts would be on one BOM line and the 50 V parts on another.
When I use a new part they don't stock, it shows up on the BOM with the in-house part number blank. Someone then assigns a part number, feeds that back to me, and I update the file. After that, my BOM system automatically fills in the in-house number for that part for subsequent designs or BOM runs.
This may sound complicated, but it's really been very nice to use.