> For the complete documentation index, see [llms.txt](https://beetle-studios.gitbook.io/beetle-studios-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://beetle-studios.gitbook.io/beetle-studios-docs/beetle-studios/brewery/installation.md).

# Installation

This page is a **step-by-step install** for **bs\_brewery** on FiveM. Item definitions are large; you **copy them from the resource files** listed below and **merge** them into your inventory’s items file (or QBCore shared items). Small **reference snippets** are included here for merge shape, `server.cfg` order, and images.

***

### Before you start (checklist)

| Requirement       | Notes                                                                                                       |
| ----------------- | ----------------------------------------------------------------------------------------------------------- |
| **MLO**           | [Dolo Beer Factory](https://www.dolu-mods.com/package/4424142) — required; coordinates assume this interior |
| **ox\_lib**       | Notifications, inputs, callbacks                                                                            |
| **ox\_inventory** | Items, stashes, shop, searches — **required** for this script                                               |
| **ox\_target**    | Brewery interactions                                                                                        |
| **oxmysql**       | Database                                                                                                    |
| **Framework**     | One of: **qbx\_core** (Qbox), **qb-core** (QBCore), **es\_extended** (ESX)                                  |

***

### 1) Add the resource

1. Copy the `bs_brewery` folder into your server (for example `resources/[standalone]/bs_brewery`).
2. Do **not** rename the folder unless you know how to update **every** `nui://` / resource reference (default name is `bs_brewery`).

***

### 2) Database

1. Open your MySQL tool (HeidiSQL, phpMyAdmin, CLI, etc.).
2. Select the **same database** your `oxmysql` connection uses.
3. Run the contents of:

`bs_brewery/sql/install.sql`

**Optional (CLI example):**

```bash
mysql -u YOUR_USER -p YOUR_DATABASE < /path/to/bs_brewery/sql/install.sql
```

The `citizenid` column stores **QBCore/Qbox citizenid** or **ESX identifier**, depending on `Config.Framework`.

***

### 3) Framework setting

Edit **`bs_brewery/shared/config.lua`**:

```lua
Config.Framework = 'qbx' -- 'qbx' | 'qb' | 'esx'
```

* **Qbox:** `'qbx'`
* **QBCore:** `'qb'`
* **ESX:** `'esx'`

Set **`Config.Currency`** (`'cash'` or `'bank'`) to match how you want the shop and payouts to charge/pay.

***

### 4) Item installation (by framework)

This script expects **all item names** used in `shared/config.lua` / recipes to exist in **ox\_inventory** (even on QBCore/ESX if you use ox\_inventory for gameplay).

#### Source files in the resource

| File                             | Use when                                                                                 |
| -------------------------------- | ---------------------------------------------------------------------------------------- |
| `bs_brewery/items/ox_items.lua`  | **ox\_inventory** (Qbox, QBCore+ox, ESX+ox) — full `return { ... }` ox item table        |
| `bs_brewery/items/esx_items.lua` | **ESX + ox\_inventory** — same ox shape; keep in sync with `ox_items.lua`                |
| `bs_brewery/items/qb_items.lua`  | **QBCore `QBShared.Items`** (qb-inventory style metadata) — **not** a full `return` file |

***

#### A) Qbox (QBX) — ox\_inventory

**Target file (typical):** `ox_inventory/data/items.lua`

Here you will copy items in to your `items.lua` file in ox\_inventory.

**Steps**

1. Open **`bs_brewery/items/ox_items.lua`** in an editor.
2. Copy **only the entries** inside the main table: from the first `['pale_malt']` (or first `['...']` after `return {`) through the last item **before** the closing `}` of that file — **do not** paste a second `return {`.
3. In **`ox_inventory/data/items.lua`**, paste those lines **inside** your existing `return { ... }`, with a comma after the previous last item.
4. Ensure **recipe books** keep their `use` callbacks exactly as in the resource file (see snippet below).
5. Save, then restart **`ox_inventory`**, then **`bs_brewery`**.

**Copy Items below and Append to Data > items.lua file:**

{% code expandable="true" %}

```lua
    -- ==========================================
    -- BASE MALTS / GRAINS (sold by the pound)
    -- ==========================================
    ['pale_malt'] = {
        label = 'Pale Malt (2-Row)',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Classic American 2-row pale malt. The foundation of most beers. Sold by the pound (lb).',
    },
    ['pilsner_malt'] = {
        label = 'Pilsner Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Light German pilsner malt for crisp lagers. Sold by the pound (lb).',
    },
    ['wheat_malt'] = {
        label = 'Wheat Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Malted wheat for hefeweizens and wheat beers. Sold by the pound (lb).',
    },
    ['munich_malt'] = {
        label = 'Munich Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Adds rich, bready, malty flavors. Sold by the pound (lb).',
    },
    ['vienna_malt'] = {
        label = 'Vienna Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Slightly darker base malt with toasty notes. Sold by the pound (lb).',
    },
    ['maris_otter'] = {
        label = 'Maris Otter',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Premium English pale malt with biscuity character. Sold by the pound (lb).',
    },

    -- ==========================================
    -- SPECIALTY GRAINS (sold by the pound)
    -- ==========================================
    ['crystal_malt'] = {
        label = 'Crystal Malt 60°L',
        weight = 500,
        stack = true,
        close = true,
        description = 'Adds caramel sweetness and body. 60°L refers to 60° Lovibond (color rating), not volume. Sold by the pound (lb).',
    },
    ['chocolate_malt'] = {
        label = 'Chocolate Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Dark malt with chocolate and coffee notes. Sold by the pound (lb).',
    },
    ['roasted_barley'] = {
        label = 'Roasted Barley',
        weight = 500,
        stack = true,
        close = true,
        description = 'Unmalted barley, key for stouts. Sold by the pound (lb).',
    },
    ['black_patent'] = {
        label = 'Black Patent Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Intensely roasted for color and bitter notes. Sold by the pound (lb).',
    },
    ['carapils'] = {
        label = 'Carapils/Dextrine',
        weight = 500,
        stack = true,
        close = true,
        description = 'Improves head retention and body. Sold by the pound (lb).',
    },
    ['honey_malt'] = {
        label = 'Honey Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Sweet malt with honey-like flavors. Sold by the pound (lb).',
    },
    ['smoked_malt'] = {
        label = 'Smoked Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Beechwood smoked malt for rauchbiers. Sold by the pound (lb).',
    },
    ['oat_malt'] = {
        label = 'Oat Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Adds silky mouthfeel and body. Sold by the pound (lb).',
    },
    ['rye_malt'] = {
        label = 'Rye Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Spicy grain character. Sold by the pound (lb).',
    },
    ['acidulated_malt'] = {
        label = 'Acidulated Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Lowers mash pH naturally. Sold by the pound (lb).',
    },

    -- ==========================================
    -- HOPS (sold by the ounce)
    -- ==========================================
    ['cascade_hops'] = {
        label = 'Cascade Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Classic American hop with citrus and floral notes. Sold by the ounce (oz).',
    },
    ['centennial_hops'] = {
        label = 'Centennial Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Balanced citrus and floral hop. Sold by the ounce (oz).',
    },
    ['citra_hops'] = {
        label = 'Citra Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Intense tropical fruit and citrus. Sold by the ounce (oz).',
    },
    ['mosaic_hops'] = {
        label = 'Mosaic Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Complex berry and tropical notes. Sold by the ounce (oz).',
    },
    ['simcoe_hops'] = {
        label = 'Simcoe Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Pine, citrus, and earthy character. Sold by the ounce (oz).',
    },
    ['amarillo_hops'] = {
        label = 'Amarillo Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Orange and floral aromatics. Sold by the ounce (oz).',
    },
    ['saaz_hops'] = {
        label = 'Saaz Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Noble Czech hop with spicy, herbal notes. Sold by the ounce (oz).',
    },
    ['hallertau_hops'] = {
        label = 'Hallertau Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Traditional German noble hop. Sold by the ounce (oz).',
    },
    ['fuggle_hops'] = {
        label = 'Fuggle Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'English hop with earthy, woody character. Sold by the ounce (oz).',
    },
    ['ekg_hops'] = {
        label = 'East Kent Goldings',
        weight = 100,
        stack = true,
        close = true,
        description = 'Classic English aroma hop. Sold by the ounce (oz).',
    },
    ['galaxy_hops'] = {
        label = 'Galaxy Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Australian hop with passionfruit notes. Sold by the ounce (oz).',
    },
    ['nelson_hops'] = {
        label = 'Nelson Sauvin',
        weight = 100,
        stack = true,
        close = true,
        description = 'New Zealand hop with wine-like qualities. Sold by the ounce (oz).',
    },

    -- ==========================================
    -- YEAST (sold by the packet)
    -- ==========================================
    ['us05_yeast'] = {
        label = 'US-05 Ale Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Clean American ale yeast. Sold by the packet.',
    },
    ['s04_yeast'] = {
        label = 'S-04 English Ale',
        weight = 50,
        stack = true,
        close = true,
        description = 'English ale yeast with fruity esters. Sold by the packet.',
    },
    ['w34_yeast'] = {
        label = 'W-34/70 Lager',
        weight = 50,
        stack = true,
        close = true,
        description = 'German lager yeast for clean fermentation. Sold by the packet.',
    },
    ['belgian_yeast'] = {
        label = 'Belgian Ale Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Produces spicy, fruity Belgian character. Sold by the packet.',
    },
    ['hefeweizen_yeast'] = {
        label = 'Hefeweizen Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Creates banana and clove flavors. Sold by the packet.',
    },
    ['saison_yeast'] = {
        label = 'Saison Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Farmhouse yeast with peppery notes. Sold by the packet.',
    },
    ['brett_yeast'] = {
        label = 'Brettanomyces',
        weight = 50,
        stack = true,
        close = true,
        description = 'Wild yeast for funky, complex beers. Sold by the packet.',
    },
    ['lactobacillus'] = {
        label = 'Lactobacillus',
        weight = 50,
        stack = true,
        close = true,
        description = 'Bacteria for sour beer production. Sold by the packet.',
    },

    -- ==========================================
    -- ADJUNCTS & FLAVORS (units vary)
    -- ==========================================
    ['cane_sugar'] = {
        label = 'Cane Sugar',
        weight = 500,
        stack = true,
        close = true,
        description = 'Increases alcohol without adding body. Sold by the pound (lb).',
    },
    ['honey'] = {
        label = 'Honey',
        weight = 500,
        stack = true,
        close = true,
        description = 'Local wildflower honey. Sold by the pound (lb).',
    },
    ['maple_syrup'] = {
        label = 'Maple Syrup',
        weight = 500,
        stack = true,
        close = true,
        description = 'Grade A maple syrup. Sold by the pound (lb).',
    },
    ['lactose'] = {
        label = 'Lactose',
        weight = 500,
        stack = true,
        close = true,
        description = 'Unfermentable sugar for sweetness. Sold by the pound (lb).',
    },
    ['coffee_beans'] = {
        label = 'Coffee Beans',
        weight = 250,
        stack = true,
        close = true,
        description = 'Fresh roasted coffee beans. Sold in 4 ounce packages.',
    },
    ['cocoa_nibs'] = {
        label = 'Cocoa Nibs',
        weight = 250,
        stack = true,
        close = true,
        description = 'Raw cacao for chocolate flavor. Sold in 4 ounce packages.',
    },
    ['vanilla_beans'] = {
        label = 'Vanilla Beans',
        weight = 100,
        stack = true,
        close = true,
        description = 'Madagascar vanilla beans. Sold individually (each).',
    },
    ['oak_chips'] = {
        label = 'Oak Chips',
        weight = 250,
        stack = true,
        close = true,
        description = 'Medium toast French oak. Sold in 4 ounce packages.',
    },
    ['fruit_puree'] = {
        label = 'Fruit Puree',
        weight = 500,
        stack = true,
        close = true,
        description = 'Fresh fruit puree for brewing. Sold by the pound (lb).',
    },
    ['pumpkin_spice'] = {
        label = 'Pumpkin Spice',
        weight = 100,
        stack = true,
        close = true,
        description = 'Blend of cinnamon, nutmeg, and allspice. Sold by the ounce (oz).',
    },
    ['coriander'] = {
        label = 'Coriander',
        weight = 100,
        stack = true,
        close = true,
        description = 'Crushed coriander seeds. Sold by the ounce (oz).',
    },
    ['orange_peel'] = {
        label = 'Orange Peel',
        weight = 100,
        stack = true,
        close = true,
        description = 'Dried bitter orange peel. Sold by the ounce (oz).',
    },

    -- ==========================================
    -- PACKAGING SUPPLIES
    -- ==========================================
    ['beer_bottle'] = {
        label = 'Beer Bottle (12oz)',
        weight = 200,
        stack = true,
        close = true,
        description = 'Empty amber glass bottle. 12 fluid ounces capacity. Sold in cases of 48.',
    },
    ['bottle_cap'] = {
        label = 'Bottle Cap',
        weight = 5,
        stack = true,
        close = true,
        description = 'Oxygen-absorbing crown cap.',
    },
    ['bottle_cap_package'] = {
        label = 'Bottle Cap Package',
        weight = 250,
        stack = true,
        close = true,
        description = 'A package containing 48 bottle caps. Use to unpack.',
    },
    ['beer_label'] = {
        label = 'Beer Label',
        weight = 10,
        stack = true,
        close = true,
        description = 'Waterproof adhesive label.',
    },
    ['beer_keg'] = {
        label = 'Empty Keg (5gal)',
        weight = 5000,
        stack = true,
        close = true,
        description = 'Cornelius-style keg. 5 gallon capacity.',
    },
    ['keg_coupler'] = {
        label = 'Keg Coupler',
        weight = 500,
        stack = true,
        close = true,
        description = 'Sankey D-style coupler.',
    },
    ['beer_case'] = {
        label = 'Beer Case (24-pack)',
        weight = 500,
        stack = true,
        close = true,
        description = 'Cardboard case for 24 bottles (12oz each).',
    },

    -- ==========================================
    -- CLEANING & CHEMICALS
    -- ==========================================
    ['pbw_cleaner'] = {
        label = 'PBW Cleaner',
        weight = 500,
        stack = true,
        close = true,
        description = 'Powerful brewery wash cleaner. 16 fluid ounces.',
    },
    ['starsan'] = {
        label = 'Star San Sanitizer',
        weight = 500,
        stack = true,
        close = true,
        description = 'No-rinse sanitizer for brewing. 16 fluid ounces.',
    },

    -- ==========================================
    -- EQUIPMENT & TOOLS
    -- ==========================================
    ['hydrometer'] = {
        label = 'Hydrometer',
        weight = 100,
        stack = false,
        close = true,
        description = 'Measures specific gravity for ABV calculation.',
    },
    ['refractometer'] = {
        label = 'Refractometer',
        weight = 150,
        stack = false,
        close = true,
        description = 'Measures sugar content quickly.',
    },
    ['ph_meter'] = {
        label = 'pH Meter',
        weight = 200,
        stack = false,
        close = true,
        description = 'Digital pH meter for water chemistry.',
    },
    ['thermometer'] = {
        label = 'Digital Thermometer',
        weight = 100,
        stack = false,
        close = true,
        description = 'Precise temperature measurement.',
    },
    ['grain_scale'] = {
        label = 'Grain Scale',
        weight = 2000,
        stack = false,
        close = true,
        description = 'Digital scale for weighing ingredients.',
    },

    -- ==========================================
    -- RECIPE BOOKS (require `use` for bs_brewery UI)
    -- ==========================================
    ['recipe_book_basic'] = {
        label = 'Basic Brewing Guide',
        weight = 500,
        stack = false,
        close = true,
        description = 'Introduction to brewing basics. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_intermediate'] = {
        label = 'Intermediate Recipes',
        weight = 500,
        stack = false,
        close = true,
        description = 'Collection of intermediate beer recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_advanced'] = {
        label = 'Advanced Techniques',
        weight = 500,
        stack = false,
        close = true,
        description = 'Advanced brewing methods and recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_master'] = {
        label = "Master Brewer's Tome",
        weight = 500,
        stack = false,
        close = true,
        description = 'Expert-level brewing knowledge. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_legendary'] = {
        label = 'Legendary Brews',
        weight = 500,
        stack = false,
        close = true,
        description = 'The rarest and most complex recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },

    -- ==========================================
    -- FINISHED PRODUCTS (Generic, metadata determines type)
    -- ==========================================
    ['craft_beer_bottle'] = {
        label = 'Craft Beer Bottle',
        weight = 350,
        stack = true,
        close = false,
        description = 'A bottle of craft beer.',
        consume = 1,
    },
    ['craft_beer_keg'] = {
        label = 'Craft Beer Keg',
        weight = 20000,
        stack = false,
        close = true,
        description = 'A 5-gallon keg of craft beer.',
    },
    ['craft_beer_case'] = {
        label = 'Craft Beer Case',
        weight = 9000,
        stack = false,
        close = true,
        description = 'A case of 24 craft beers.',
    },

    -- ==========================================
    -- INTERMEDIATE BREWING ITEMS
    -- ==========================================
    ['wort_sample'] = {
        label = 'Wort Sample',
        weight = 100,
        stack = true,
        close = true,
        description = 'Sample of unfermented wort.',
    },
    ['beer_sample'] = {
        label = 'Beer Sample',
        weight = 100,
        stack = true,
        close = true,
        description = 'Sample of beer for quality testing.',
    },
    ['milled_grain'] = {
        label = 'Milled Grain',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Crushed grain ready for mashing.',
    },
}
```

{% endcode %}

**Recipe books — `use` must call the server (copy as-is if missing):**

```lua
['recipe_book_basic'] = {
    label = 'Basic Brewing Guide',
    weight = 500,
    stack = false,
    close = true,
    description = 'Introduction to brewing basics. Right-click to use.',
    use = function(event, item, inventory, slot, data)
        TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
    end,
},
```

Repeat the same `use` pattern for: `recipe_book_intermediate`, `recipe_book_advanced`, `recipe_book_master`, `recipe_book_legendary` (full blocks are in `items/ox_items.lua`).

**Item images (ox\_inventory)**

PNG files ship under **`bs_brewery/items/*.png`**. If icons do not show, add a `client` block per item (example):

```lua
['pale_malt'] = {
    label = 'Pale Malt (2-Row)',
    weight = 1000,
    stack = true,
    close = true,
    description = '...',
    client = {
        image = 'nui://bs_brewery/items/pale_malt.png',
    },
},
```

If your inventory already resolves images by **item name** + default path, you may not need `client.image`.

***

#### B) QBCore — ox\_inventory (recommended)

If players use **ox\_inventory** on QBCore:

1. Set `Config.Framework = 'qb'` in **`bs_brewery/shared/config.lua`**.
2. Merge **`bs_brewery/items/ox_items.lua`** into **`ox_inventory/data/items.lua`** using the **same steps as section A** (ox format is identical).

You do **not** need `qb_items.lua` for ox\_inventory-only setups.

***

#### C) QBCore — `QBShared.Items` (qb-inventory / classic QB item table)

Use this path if your stack still relies on **`qb-core/shared/items.lua`** (or a merged items file) with **`['item'] = { ['name'] = ... }`** shape.

**Target file (typical):** `qb-core/shared/items.lua` inside `QBShared.Items = { ... }`.

**Steps**

1. Open **`bs_brewery/items/qb_items.lua`**.
2. **Delete the template dummy block** at the top (`['item_name'] = { ... },`) — do **not** add that to `QBShared.Items`.
3. Copy **all real** entries from `['pale_malt']` through the last brewery item.
4. Paste inside **`QBShared.Items = { ... }`** with valid commas between entries.
5. Ensure images exist where your inventory expects them (often `qb-inventory/html/images` or your inventory’s image folder); filenames in the resource use **`itemname.png`**.
6. Restart **`qb-core`** (or your items resource) and **`bs_brewery`**.

**Copy Items below and Append to Data > items.lua file:**

{% code expandable="true" %}

```lua
    ['item_name'] = {
        ['name'] = 'item_name',
        ['label'] = "item_name",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'item_name.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "",
    },

    ['pale_malt'] = {
        ['name'] = 'pale_malt',
        ['label'] = "Pale Malt (2-Row)",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'pale_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Classic American 2-row pale malt. The foundation of most beers. Sold by the pound (lb).",
    },

    ['pilsner_malt'] = {
        ['name'] = 'pilsner_malt',
        ['label'] = "Pilsner Malt",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'pilsner_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Light German pilsner malt for crisp lagers. Sold by the pound (lb).",
    },

    ['wheat_malt'] = {
        ['name'] = 'wheat_malt',
        ['label'] = "Wheat Malt",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'wheat_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Malted wheat for hefeweizens and wheat beers. Sold by the pound (lb).",
    },

    ['munich_malt'] = {
        ['name'] = 'munich_malt',
        ['label'] = "Munich Malt",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'munich_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Adds rich, bready, malty flavors. Sold by the pound (lb).",
    },

    ['vienna_malt'] = {
        ['name'] = 'vienna_malt',
        ['label'] = "Vienna Malt",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'vienna_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Slightly darker base malt with toasty notes. Sold by the pound (lb).",
    },

    ['maris_otter'] = {
        ['name'] = 'maris_otter',
        ['label'] = "Maris Otter",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'maris_otter.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Premium English pale malt with biscuity character. Sold by the pound (lb).",
    },

    ['crystal_malt'] = {
        ['name'] = 'crystal_malt',
        ['label'] = "Crystal Malt 60°L",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'crystal_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Adds caramel sweetness and body. 60°L refers to 60° Lovibond (color rating), not volume. Sold by the pound (lb).",
    },

    ['chocolate_malt'] = {
        ['name'] = 'chocolate_malt',
        ['label'] = "Chocolate Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'chocolate_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Dark malt with chocolate and coffee notes. Sold by the pound (lb).",
    },

    ['roasted_barley'] = {
        ['name'] = 'roasted_barley',
        ['label'] = "Roasted Barley",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'roasted_barley.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Unmalted barley, key for stouts. Sold by the pound (lb).",
    },

    ['black_patent'] = {
        ['name'] = 'black_patent',
        ['label'] = "Black Patent Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'black_patent.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Intensely roasted for color and bitter notes. Sold by the pound (lb).",
    },

    ['carapils'] = {
        ['name'] = 'carapils',
        ['label'] = "Carapils/Dextrine",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'carapils.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Improves head retention and body. Sold by the pound (lb).",
    },

    ['honey_malt'] = {
        ['name'] = 'honey_malt',
        ['label'] = "Honey Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'honey_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Sweet malt with honey-like flavors. Sold by the pound (lb).",
    },

    ['smoked_malt'] = {
        ['name'] = 'smoked_malt',
        ['label'] = "Smoked Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'smoked_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Beechwood smoked malt for rauchbiers. Sold by the pound (lb).",
    },

    ['oat_malt'] = {
        ['name'] = 'oat_malt',
        ['label'] = "Oat Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'oat_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Adds silky mouthfeel and body. Sold by the pound (lb).",
    },

    ['rye_malt'] = {
        ['name'] = 'rye_malt',
        ['label'] = "Rye Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'rye_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Spicy grain character. Sold by the pound (lb).",
    },

    ['acidulated_malt'] = {
        ['name'] = 'acidulated_malt',
        ['label'] = "Acidulated Malt",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'acidulated_malt.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Lowers mash pH naturally. Sold by the pound (lb).",
    },

    ['cascade_hops'] = {
        ['name'] = 'cascade_hops',
        ['label'] = "Cascade Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'cascade_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Classic American hop with citrus and floral notes. Sold by the ounce (oz).",
    },

    ['centennial_hops'] = {
        ['name'] = 'centennial_hops',
        ['label'] = "Centennial Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'centennial_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Balanced citrus and floral hop. Sold by the ounce (oz).",
    },

    ['citra_hops'] = {
        ['name'] = 'citra_hops',
        ['label'] = "Citra Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'citra_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Intense tropical fruit and citrus. Sold by the ounce (oz).",
    },

    ['mosaic_hops'] = {
        ['name'] = 'mosaic_hops',
        ['label'] = "Mosaic Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'mosaic_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Complex berry and tropical notes. Sold by the ounce (oz).",
    },

    ['simcoe_hops'] = {
        ['name'] = 'simcoe_hops',
        ['label'] = "Simcoe Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'simcoe_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Pine, citrus, and earthy character. Sold by the ounce (oz).",
    },

    ['amarillo_hops'] = {
        ['name'] = 'amarillo_hops',
        ['label'] = "Amarillo Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'amarillo_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Orange and floral aromatics. Sold by the ounce (oz).",
    },

    ['saaz_hops'] = {
        ['name'] = 'saaz_hops',
        ['label'] = "Saaz Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'saaz_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Noble Czech hop with spicy, herbal notes. Sold by the ounce (oz).",
    },

    ['hallertau_hops'] = {
        ['name'] = 'hallertau_hops',
        ['label'] = "Hallertau Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'hallertau_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Traditional German noble hop. Sold by the ounce (oz).",
    },

    ['fuggle_hops'] = {
        ['name'] = 'fuggle_hops',
        ['label'] = "Fuggle Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'fuggle_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "English hop with earthy, woody character. Sold by the ounce (oz).",
    },

    ['ekg_hops'] = {
        ['name'] = 'ekg_hops',
        ['label'] = "East Kent Goldings",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'ekg_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Classic English aroma hop. Sold by the ounce (oz).",
    },

    ['galaxy_hops'] = {
        ['name'] = 'galaxy_hops',
        ['label'] = "Galaxy Hops",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'galaxy_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Australian hop with passionfruit notes. Sold by the ounce (oz).",
    },

    ['nelson_hops'] = {
        ['name'] = 'nelson_hops',
        ['label'] = "Nelson Sauvin",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'nelson_hops.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "New Zealand hop with wine-like qualities. Sold by the ounce (oz).",
    },

    ['us05_yeast'] = {
        ['name'] = 'us05_yeast',
        ['label'] = "US-05 Ale Yeast",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'us05_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Clean American ale yeast. Sold by the packet.",
    },

    ['s04_yeast'] = {
        ['name'] = 's04_yeast',
        ['label'] = "S-04 English Ale",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 's04_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "English ale yeast with fruity esters. Sold by the packet.",
    },

    ['w34_yeast'] = {
        ['name'] = 'w34_yeast',
        ['label'] = "W-34/70 Lager",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'w34_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "German lager yeast for clean fermentation. Sold by the packet.",
    },

    ['belgian_yeast'] = {
        ['name'] = 'belgian_yeast',
        ['label'] = "Belgian Ale Yeast",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'belgian_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Produces spicy, fruity Belgian character. Sold by the packet.",
    },

    ['hefeweizen_yeast'] = {
        ['name'] = 'hefeweizen_yeast',
        ['label'] = "Hefeweizen Yeast",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'hefeweizen_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Creates banana and clove flavors. Sold by the packet.",
    },

    ['saison_yeast'] = {
        ['name'] = 'saison_yeast',
        ['label'] = "Saison Yeast",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'saison_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Farmhouse yeast with peppery notes. Sold by the packet.",
    },

    ['brett_yeast'] = {
        ['name'] = 'brett_yeast',
        ['label'] = "Brettanomyces",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'brett_yeast.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Wild yeast for funky, complex beers. Sold by the packet.",
    },

    ['lactobacillus'] = {
        ['name'] = 'lactobacillus',
        ['label'] = "Lactobacillus",
        ['weight'] = 50,
        ['type'] = 'item',
        ['image'] = 'lactobacillus.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Bacteria for sour beer production. Sold by the packet.",
    },

    ['cane_sugar'] = {
        ['name'] = 'cane_sugar',
        ['label'] = "Cane Sugar",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'cane_sugar.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Increases alcohol without adding body. Sold by the pound (lb).",
    },

    ['honey'] = {
        ['name'] = 'honey',
        ['label'] = "Honey",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'honey.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Local wildflower honey. Sold by the pound (lb).",
    },

    ['maple_syrup'] = {
        ['name'] = 'maple_syrup',
        ['label'] = "Maple Syrup",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'maple_syrup.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Grade A maple syrup. Sold by the pound (lb).",
    },

    ['lactose'] = {
        ['name'] = 'lactose',
        ['label'] = "Lactose",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'lactose.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Unfermentable sugar for sweetness. Sold by the pound (lb).",
    },

    ['coffee_beans'] = {
        ['name'] = 'coffee_beans',
        ['label'] = "Coffee Beans",
        ['weight'] = 250,
        ['type'] = 'item',
        ['image'] = 'coffee_beans.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Fresh roasted coffee beans. Sold in 4 ounce packages.",
    },

    ['cocoa_nibs'] = {
        ['name'] = 'cocoa_nibs',
        ['label'] = "Cocoa Nibs",
        ['weight'] = 250,
        ['type'] = 'item',
        ['image'] = 'cocoa_nibs.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Raw cacao for chocolate flavor. Sold in 4 ounce packages.",
    },

    ['vanilla_beans'] = {
        ['name'] = 'vanilla_beans',
        ['label'] = "Vanilla Beans",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'vanilla_beans.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Madagascar vanilla beans. Sold individually (each).",
    },

    ['oak_chips'] = {
        ['name'] = 'oak_chips',
        ['label'] = "Oak Chips",
        ['weight'] = 250,
        ['type'] = 'item',
        ['image'] = 'oak_chips.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Medium toast French oak. Sold in 4 ounce packages.",
    },

    ['fruit_puree'] = {
        ['name'] = 'fruit_puree',
        ['label'] = "Fruit Puree",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'fruit_puree.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Fresh fruit puree for brewing. Sold by the pound (lb).",
    },

    ['pumpkin_spice'] = {
        ['name'] = 'pumpkin_spice',
        ['label'] = "Pumpkin Spice",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'pumpkin_spice.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Blend of cinnamon, nutmeg, and allspice. Sold by the ounce (oz).",
    },

    ['coriander'] = {
        ['name'] = 'coriander',
        ['label'] = "Coriander",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'coriander.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Crushed coriander seeds. Sold by the ounce (oz).",
    },

    ['orange_peel'] = {
        ['name'] = 'orange_peel',
        ['label'] = "Orange Peel",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'orange_peel.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Dried bitter orange peel. Sold by the ounce (oz).",
    },

    ['beer_bottle'] = {
        ['name'] = 'beer_bottle',
        ['label'] = "Beer Bottle (12oz)",
        ['weight'] = 200,
        ['type'] = 'item',
        ['image'] = 'beer_bottle.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Empty amber glass bottle. 12 fluid ounces capacity. Sold in cases of 48.",
    },

    ['bottle_cap'] = {
        ['name'] = 'bottle_cap',
        ['label'] = "Bottle Cap",
        ['weight'] = 5,
        ['type'] = 'item',
        ['image'] = 'bottle_cap.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Oxygen-absorbing crown cap.",
    },

    ['bottle_cap_package'] = {
        ['name'] = 'bottle_cap_package',
        ['label'] = "Bottle Cap Package",
        ['weight'] = 250,
        ['type'] = 'item',
        ['image'] = 'bottle_cap_package.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "A package containing 48 bottle caps. Use to unpack.",
    },

    ['beer_label'] = {
        ['name'] = 'beer_label',
        ['label'] = "Beer Label",
        ['weight'] = 10,
        ['type'] = 'item',
        ['image'] = 'beer_label.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Waterproof adhesive label.",
    },

    ['beer_keg'] = {
        ['name'] = 'beer_keg',
        ['label'] = "Empty Keg (5gal)",
        ['weight'] = 5000,
        ['type'] = 'item',
        ['image'] = 'beer_keg.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Cornelius-style keg. 5 gallon capacity.",
    },

    ['keg_coupler'] = {
        ['name'] = 'keg_coupler',
        ['label'] = "Keg Coupler",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'keg_coupler.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Sankey D-style coupler.",
    },

    ['beer_case'] = {
        ['name'] = 'beer_case',
        ['label'] = "Beer Case (24-pack)",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'beer_case.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Cardboard case for 24 bottles (12oz each).",
    },

    ['pbw_cleaner'] = {
        ['name'] = 'pbw_cleaner',
        ['label'] = "PBW Cleaner",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'pbw_cleaner.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Powerful brewery wash cleaner. 16 fluid ounces.",
    },

    ['starsan'] = {
        ['name'] = 'starsan',
        ['label'] = "Star San Sanitizer",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'starsan.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "No-rinse sanitizer for brewing. 16 fluid ounces.",
    },

    ['hydrometer'] = {
        ['name'] = 'hydrometer',
        ['label'] = "Hydrometer",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'hydrometer.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Measures specific gravity for ABV calculation.",
    },

    ['refractometer'] = {
        ['name'] = 'refractometer',
        ['label'] = "Refractometer",
        ['weight'] = 150,
        ['type'] = 'item',
        ['image'] = 'refractometer.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Measures sugar content quickly.",
    },

    ['ph_meter'] = {
        ['name'] = 'ph_meter',
        ['label'] = "pH Meter",
        ['weight'] = 200,
        ['type'] = 'item',
        ['image'] = 'ph_meter.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Digital pH meter for water chemistry.",
    },

    ['thermometer'] = {
        ['name'] = 'thermometer',
        ['label'] = "Digital Thermometer",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'thermometer.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Precise temperature measurement.",
    },

    ['grain_scale'] = {
        ['name'] = 'grain_scale',
        ['label'] = "Grain Scale",
        ['weight'] = 2000,
        ['type'] = 'item',
        ['image'] = 'grain_scale.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Digital scale for weighing ingredients.",
    },

    ['recipe_book_basic'] = {
        ['name'] = 'recipe_book_basic',
        ['label'] = "Basic Brewing Guide",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'recipe_book_basic.png',
        ['unique'] = false,
        ['useable'] = true,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Introduction to brewing basics. Right-click to use.",
    },

    ['recipe_book_intermediate'] = {
        ['name'] = 'recipe_book_intermediate',
        ['label'] = "Intermediate Recipes",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'recipe_book_intermediate.png',
        ['unique'] = false,
        ['useable'] = true,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Collection of intermediate beer recipes. Right-click to use.",
    },

    ['recipe_book_advanced'] = {
        ['name'] = 'recipe_book_advanced',
        ['label'] = "Advanced Techniques",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'recipe_book_advanced.png',
        ['unique'] = false,
        ['useable'] = true,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Advanced brewing methods and recipes. Right-click to use.",
    },

    ['recipe_book_master'] = {
        ['name'] = 'recipe_book_master',
        ['label'] = "Master Brewer's Tome",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'recipe_book_master.png',
        ['unique'] = false,
        ['useable'] = true,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Expert-level brewing knowledge. Right-click to use.",
    },

    ['recipe_book_legendary'] = {
        ['name'] = 'recipe_book_legendary',
        ['label'] = "Legendary Brews",
        ['weight'] = 500,
        ['type'] = 'item',
        ['image'] = 'recipe_book_legendary.png',
        ['unique'] = false,
        ['useable'] = true,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "The rarest and most complex recipes. Right-click to use.",
    },

    ['craft_beer_bottle'] = {
        ['name'] = 'craft_beer_bottle',
        ['label'] = "Craft Beer Bottle",
        ['weight'] = 350,
        ['type'] = 'item',
        ['image'] = 'craft_beer_bottle.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "A bottle of craft beer.",
    },

    ['craft_beer_keg'] = {
        ['name'] = 'craft_beer_keg',
        ['label'] = "Craft Beer Keg",
        ['weight'] = 20000,
        ['type'] = 'item',
        ['image'] = 'craft_beer_keg.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "A 5-gallon keg of craft beer.",
    },

    ['craft_beer_case'] = {
        ['name'] = 'craft_beer_case',
        ['label'] = "Craft Beer Case",
        ['weight'] = 9000,
        ['type'] = 'item',
        ['image'] = 'craft_beer_case.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "A case of 24 craft beers.",
    },

    ['wort_sample'] = {
        ['name'] = 'wort_sample',
        ['label'] = "Wort Sample",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'wort_sample.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Sample of unfermented wort.",
    },

    ['beer_sample'] = {
        ['name'] = 'beer_sample',
        ['label'] = "Beer Sample",
        ['weight'] = 100,
        ['type'] = 'item',
        ['image'] = 'beer_sample.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Sample of beer for quality testing.",
    },

    ['milled_grain'] = {
        ['name'] = 'milled_grain',
        ['label'] = "Milled Grain",
        ['weight'] = 1000,
        ['type'] = 'item',
        ['image'] = 'milled_grain.png',
        ['unique'] = false,
        ['useable'] = false,
        ['shouldClose'] = true,
        ['combinable'] = nil,
        ['description'] = "Crushed grain ready for mashing.",
    },**
}
```

{% endcode %}

**Note:** Recipe books in **`qb_items.lua`** may not include ox-style `use` functions. If you use **ox\_inventory** for books, prefer merging **`ox_items.lua`** recipe book entries (with `use`) into **ox\_inventory** instead.

***

#### D) ESX — ox\_inventory

1. Set `Config.Framework = 'esx'` in **`bs_brewery/shared/config.lua`**.
2. Merge **`bs_brewery/items/esx_items.lua`** (or **`ox_items.lua`** — same ox table shape) into **`ox_inventory/data/items.lua`** using the **same merge method as section A**.
3. Restart **`ox_inventory`**, then **`bs_brewery`**.

`Config.Currency = 'cash'` maps to the ESX **`money`** account in the server bridge; `'bank'` maps to **`bank`**.

{% code expandable="true" %}

```lua
    -- ==========================================
    -- BASE MALTS / GRAINS (sold by the pound)
    -- ==========================================
    ['pale_malt'] = {
        label = 'Pale Malt (2-Row)',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Classic American 2-row pale malt. The foundation of most beers. Sold by the pound (lb).',
    },
    ['pilsner_malt'] = {
        label = 'Pilsner Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Light German pilsner malt for crisp lagers. Sold by the pound (lb).',
    },
    ['wheat_malt'] = {
        label = 'Wheat Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Malted wheat for hefeweizens and wheat beers. Sold by the pound (lb).',
    },
    ['munich_malt'] = {
        label = 'Munich Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Adds rich, bready, malty flavors. Sold by the pound (lb).',
    },
    ['vienna_malt'] = {
        label = 'Vienna Malt',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Slightly darker base malt with toasty notes. Sold by the pound (lb).',
    },
    ['maris_otter'] = {
        label = 'Maris Otter',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Premium English pale malt with biscuity character. Sold by the pound (lb).',
    },

    -- ==========================================
    -- SPECIALTY GRAINS (sold by the pound)
    -- ==========================================
    ['crystal_malt'] = {
        label = 'Crystal Malt 60°L',
        weight = 500,
        stack = true,
        close = true,
        description = 'Adds caramel sweetness and body. 60°L refers to 60° Lovibond (color rating), not volume. Sold by the pound (lb).',
    },
    ['chocolate_malt'] = {
        label = 'Chocolate Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Dark malt with chocolate and coffee notes. Sold by the pound (lb).',
    },
    ['roasted_barley'] = {
        label = 'Roasted Barley',
        weight = 500,
        stack = true,
        close = true,
        description = 'Unmalted barley, key for stouts. Sold by the pound (lb).',
    },
    ['black_patent'] = {
        label = 'Black Patent Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Intensely roasted for color and bitter notes. Sold by the pound (lb).',
    },
    ['carapils'] = {
        label = 'Carapils/Dextrine',
        weight = 500,
        stack = true,
        close = true,
        description = 'Improves head retention and body. Sold by the pound (lb).',
    },
    ['honey_malt'] = {
        label = 'Honey Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Sweet malt with honey-like flavors. Sold by the pound (lb).',
    },
    ['smoked_malt'] = {
        label = 'Smoked Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Beechwood smoked malt for rauchbiers. Sold by the pound (lb).',
    },
    ['oat_malt'] = {
        label = 'Oat Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Adds silky mouthfeel and body. Sold by the pound (lb).',
    },
    ['rye_malt'] = {
        label = 'Rye Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Spicy grain character. Sold by the pound (lb).',
    },
    ['acidulated_malt'] = {
        label = 'Acidulated Malt',
        weight = 500,
        stack = true,
        close = true,
        description = 'Lowers mash pH naturally. Sold by the pound (lb).',
    },

    -- ==========================================
    -- HOPS (sold by the ounce)
    -- ==========================================
    ['cascade_hops'] = {
        label = 'Cascade Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Classic American hop with citrus and floral notes. Sold by the ounce (oz).',
    },
    ['centennial_hops'] = {
        label = 'Centennial Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Balanced citrus and floral hop. Sold by the ounce (oz).',
    },
    ['citra_hops'] = {
        label = 'Citra Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Intense tropical fruit and citrus. Sold by the ounce (oz).',
    },
    ['mosaic_hops'] = {
        label = 'Mosaic Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Complex berry and tropical notes. Sold by the ounce (oz).',
    },
    ['simcoe_hops'] = {
        label = 'Simcoe Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Pine, citrus, and earthy character. Sold by the ounce (oz).',
    },
    ['amarillo_hops'] = {
        label = 'Amarillo Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Orange and floral aromatics. Sold by the ounce (oz).',
    },
    ['saaz_hops'] = {
        label = 'Saaz Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Noble Czech hop with spicy, herbal notes. Sold by the ounce (oz).',
    },
    ['hallertau_hops'] = {
        label = 'Hallertau Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Traditional German noble hop. Sold by the ounce (oz).',
    },
    ['fuggle_hops'] = {
        label = 'Fuggle Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'English hop with earthy, woody character. Sold by the ounce (oz).',
    },
    ['ekg_hops'] = {
        label = 'East Kent Goldings',
        weight = 100,
        stack = true,
        close = true,
        description = 'Classic English aroma hop. Sold by the ounce (oz).',
    },
    ['galaxy_hops'] = {
        label = 'Galaxy Hops',
        weight = 100,
        stack = true,
        close = true,
        description = 'Australian hop with passionfruit notes. Sold by the ounce (oz).',
    },
    ['nelson_hops'] = {
        label = 'Nelson Sauvin',
        weight = 100,
        stack = true,
        close = true,
        description = 'New Zealand hop with wine-like qualities. Sold by the ounce (oz).',
    },

    -- ==========================================
    -- YEAST (sold by the packet)
    -- ==========================================
    ['us05_yeast'] = {
        label = 'US-05 Ale Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Clean American ale yeast. Sold by the packet.',
    },
    ['s04_yeast'] = {
        label = 'S-04 English Ale',
        weight = 50,
        stack = true,
        close = true,
        description = 'English ale yeast with fruity esters. Sold by the packet.',
    },
    ['w34_yeast'] = {
        label = 'W-34/70 Lager',
        weight = 50,
        stack = true,
        close = true,
        description = 'German lager yeast for clean fermentation. Sold by the packet.',
    },
    ['belgian_yeast'] = {
        label = 'Belgian Ale Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Produces spicy, fruity Belgian character. Sold by the packet.',
    },
    ['hefeweizen_yeast'] = {
        label = 'Hefeweizen Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Creates banana and clove flavors. Sold by the packet.',
    },
    ['saison_yeast'] = {
        label = 'Saison Yeast',
        weight = 50,
        stack = true,
        close = true,
        description = 'Farmhouse yeast with peppery notes. Sold by the packet.',
    },
    ['brett_yeast'] = {
        label = 'Brettanomyces',
        weight = 50,
        stack = true,
        close = true,
        description = 'Wild yeast for funky, complex beers. Sold by the packet.',
    },
    ['lactobacillus'] = {
        label = 'Lactobacillus',
        weight = 50,
        stack = true,
        close = true,
        description = 'Bacteria for sour beer production. Sold by the packet.',
    },

    -- ==========================================
    -- ADJUNCTS & FLAVORS (units vary)
    -- ==========================================
    ['cane_sugar'] = {
        label = 'Cane Sugar',
        weight = 500,
        stack = true,
        close = true,
        description = 'Increases alcohol without adding body. Sold by the pound (lb).',
    },
    ['honey'] = {
        label = 'Honey',
        weight = 500,
        stack = true,
        close = true,
        description = 'Local wildflower honey. Sold by the pound (lb).',
    },
    ['maple_syrup'] = {
        label = 'Maple Syrup',
        weight = 500,
        stack = true,
        close = true,
        description = 'Grade A maple syrup. Sold by the pound (lb).',
    },
    ['lactose'] = {
        label = 'Lactose',
        weight = 500,
        stack = true,
        close = true,
        description = 'Unfermentable sugar for sweetness. Sold by the pound (lb).',
    },
    ['coffee_beans'] = {
        label = 'Coffee Beans',
        weight = 250,
        stack = true,
        close = true,
        description = 'Fresh roasted coffee beans. Sold in 4 ounce packages.',
    },
    ['cocoa_nibs'] = {
        label = 'Cocoa Nibs',
        weight = 250,
        stack = true,
        close = true,
        description = 'Raw cacao for chocolate flavor. Sold in 4 ounce packages.',
    },
    ['vanilla_beans'] = {
        label = 'Vanilla Beans',
        weight = 100,
        stack = true,
        close = true,
        description = 'Madagascar vanilla beans. Sold individually (each).',
    },
    ['oak_chips'] = {
        label = 'Oak Chips',
        weight = 250,
        stack = true,
        close = true,
        description = 'Medium toast French oak. Sold in 4 ounce packages.',
    },
    ['fruit_puree'] = {
        label = 'Fruit Puree',
        weight = 500,
        stack = true,
        close = true,
        description = 'Fresh fruit puree for brewing. Sold by the pound (lb).',
    },
    ['pumpkin_spice'] = {
        label = 'Pumpkin Spice',
        weight = 100,
        stack = true,
        close = true,
        description = 'Blend of cinnamon, nutmeg, and allspice. Sold by the ounce (oz).',
    },
    ['coriander'] = {
        label = 'Coriander',
        weight = 100,
        stack = true,
        close = true,
        description = 'Crushed coriander seeds. Sold by the ounce (oz).',
    },
    ['orange_peel'] = {
        label = 'Orange Peel',
        weight = 100,
        stack = true,
        close = true,
        description = 'Dried bitter orange peel. Sold by the ounce (oz).',
    },

    -- ==========================================
    -- PACKAGING SUPPLIES
    -- ==========================================
    ['beer_bottle'] = {
        label = 'Beer Bottle (12oz)',
        weight = 200,
        stack = true,
        close = true,
        description = 'Empty amber glass bottle. 12 fluid ounces capacity. Sold in cases of 48.',
    },
    ['bottle_cap'] = {
        label = 'Bottle Cap',
        weight = 5,
        stack = true,
        close = true,
        description = 'Oxygen-absorbing crown cap.',
    },
    ['bottle_cap_package'] = {
        label = 'Bottle Cap Package',
        weight = 250,
        stack = true,
        close = true,
        description = 'A package containing 48 bottle caps. Use to unpack.',
    },
    ['beer_label'] = {
        label = 'Beer Label',
        weight = 10,
        stack = true,
        close = true,
        description = 'Waterproof adhesive label.',
    },
    ['beer_keg'] = {
        label = 'Empty Keg (5gal)',
        weight = 5000,
        stack = true,
        close = true,
        description = 'Cornelius-style keg. 5 gallon capacity.',
    },
    ['keg_coupler'] = {
        label = 'Keg Coupler',
        weight = 500,
        stack = true,
        close = true,
        description = 'Sankey D-style coupler.',
    },
    ['beer_case'] = {
        label = 'Beer Case (24-pack)',
        weight = 500,
        stack = true,
        close = true,
        description = 'Cardboard case for 24 bottles (12oz each).',
    },

    -- ==========================================
    -- CLEANING & CHEMICALS
    -- ==========================================
    ['pbw_cleaner'] = {
        label = 'PBW Cleaner',
        weight = 500,
        stack = true,
        close = true,
        description = 'Powerful brewery wash cleaner. 16 fluid ounces.',
    },
    ['starsan'] = {
        label = 'Star San Sanitizer',
        weight = 500,
        stack = true,
        close = true,
        description = 'No-rinse sanitizer for brewing. 16 fluid ounces.',
    },

    -- ==========================================
    -- EQUIPMENT & TOOLS
    -- ==========================================
    ['hydrometer'] = {
        label = 'Hydrometer',
        weight = 100,
        stack = false,
        close = true,
        description = 'Measures specific gravity for ABV calculation.',
    },
    ['refractometer'] = {
        label = 'Refractometer',
        weight = 150,
        stack = false,
        close = true,
        description = 'Measures sugar content quickly.',
    },
    ['ph_meter'] = {
        label = 'pH Meter',
        weight = 200,
        stack = false,
        close = true,
        description = 'Digital pH meter for water chemistry.',
    },
    ['thermometer'] = {
        label = 'Digital Thermometer',
        weight = 100,
        stack = false,
        close = true,
        description = 'Precise temperature measurement.',
    },
    ['grain_scale'] = {
        label = 'Grain Scale',
        weight = 2000,
        stack = false,
        close = true,
        description = 'Digital scale for weighing ingredients.',
    },

    -- ==========================================
    -- RECIPE BOOKS (require `use` for bs_brewery UI)
    -- ==========================================
    ['recipe_book_basic'] = {
        label = 'Basic Brewing Guide',
        weight = 500,
        stack = false,
        close = true,
        description = 'Introduction to brewing basics. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_intermediate'] = {
        label = 'Intermediate Recipes',
        weight = 500,
        stack = false,
        close = true,
        description = 'Collection of intermediate beer recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_advanced'] = {
        label = 'Advanced Techniques',
        weight = 500,
        stack = false,
        close = true,
        description = 'Advanced brewing methods and recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_master'] = {
        label = "Master Brewer's Tome",
        weight = 500,
        stack = false,
        close = true,
        description = 'Expert-level brewing knowledge. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },
    ['recipe_book_legendary'] = {
        label = 'Legendary Brews',
        weight = 500,
        stack = false,
        close = true,
        description = 'The rarest and most complex recipes. Right-click to use.',
        use = function(event, item, inventory, slot, data)
            TriggerServerEvent('bs_brewery:server:useRecipeBook', item.name)
        end,
    },

    -- ==========================================
    -- FINISHED PRODUCTS (Generic, metadata determines type)
    -- ==========================================
    ['craft_beer_bottle'] = {
        label = 'Craft Beer Bottle',
        weight = 350,
        stack = true,
        close = false,
        description = 'A bottle of craft beer.',
        consume = 1,
    },
    ['craft_beer_keg'] = {
        label = 'Craft Beer Keg',
        weight = 20000,
        stack = false,
        close = true,
        description = 'A 5-gallon keg of craft beer.',
    },
    ['craft_beer_case'] = {
        label = 'Craft Beer Case',
        weight = 9000,
        stack = false,
        close = true,
        description = 'A case of 24 craft beers.',
    },

    -- ==========================================
    -- INTERMEDIATE BREWING ITEMS
    -- ==========================================
    ['wort_sample'] = {
        label = 'Wort Sample',
        weight = 100,
        stack = true,
        close = true,
        description = 'Sample of unfermented wort.',
    },
    ['beer_sample'] = {
        label = 'Beer Sample',
        weight = 100,
        stack = true,
        close = true,
        description = 'Sample of beer for quality testing.',
    },
    ['milled_grain'] = {
        label = 'Milled Grain',
        weight = 1000,
        stack = true,
        close = true,
        description = 'Crushed grain ready for mashing.',
    },
```

{% endcode %}

***

### 5) `server.cfg` load order

Start dependencies **before** `bs_brewery`. Example:

```cfg
ensure oxmysql
ensure ox_lib
ensure ox_inventory
ensure ox_target

# Framework (pick one ecosystem)
ensure qbx_core
# OR: ensure qb-core
# OR: ensure es_extended

# MLO (example — use your map resource name)
ensure dolo_beer_factory

ensure bs_brewery
```

Adjust names to match your **actual** resource folder names.

***

### 6) Verify

1. Join the server, go to the brewery MLO.
2. Open **brewery storage** / **shop** — if items are missing, ox\_inventory will error or refuse; fix merges.
3. Use a **recipe book** from inventory — the UI should open; if not, confirm **`use`** → **`bs_brewery:server:useRecipeBook`** on those items in **ox\_inventory**.
4. Start a short mash/boil test to confirm callbacks and DB tables respond.

***

### 7) Troubleshooting

| Symptom                    | Things to check                                                                                         |
| -------------------------- | ------------------------------------------------------------------------------------------------------- |
| Shop / stash “cannot open” | Item names in **`ox_inventory/data/items.lua`** missing or typo’d vs `shared/config.lua`                |
| Recipe book does nothing   | `use` missing on book items in **ox\_inventory**; event must be **`bs_brewery:server:useRecipeBook`**   |
| Wrong framework errors     | `Config.Framework` matches your core; core starts **before** `bs_brewery`                               |
| No images                  | Add `client.image` with `nui://bs_brewery/items/<name>.png`, or match your inventory’s image convention |
| DB errors                  | Re-run **`sql/install.sql`**; confirm **oxmysql** points at that DB                                     |
