Magento 2 Shipping Table Rates: Setup, CSV & Beyond
Table-rate shipping in Magento 2: what is native, and where it stops
Magento 2 does include table-rate shipping natively: one CSV per website, keyed on destination plus a single condition — weight, order subtotal or item count — producing one rate at checkout. You configure it under Stores → Configuration → Sales → Delivery Methods → Table Rates, and the CSV import and export buttons only appear once you switch the configuration scope from Default to a specific website, which is the step almost everyone misses.
That native carrier is enough for simple national shipping bands. If your shipping is more real than that — multiple carriers with different tables, free-shipping thresholds by region, weight and price considered together — the native carrier cannot express it, and most stores end up hard-coding workarounds. This guide covers the native setup properly, the CSV structure that keeps you sane, and what an advanced multi-table setup looks like.
Native table rates, step by step
- Enable the carrier and pick the condition. Under Stores → Configuration → Sales → Delivery Methods → Table Rates, enable the method and choose the condition: weight vs destination, price vs destination, or number of items vs destination. One condition type per website — this is the limit you will meet later.
- Switch scope to your website. Use the scope selector at the top left of the configuration page to change from Default Config to the website. Only then do the Export CSV and Import buttons appear, because native table rates are stored per website.
- Export the sample CSV and fill it in. One row per destination band: country, region, postcode, condition value, and your rate. Use
*as an explicit wildcard rather than leaving cells blank. - Import, save, and flush cache. Upload the file, save the configuration, then
bin/magento cache:flushso checkout picks up the new rates. - Test in the cart with representative addresses — including addresses at the boundaries of your bands, not just one that you know works.
The CSV, column by column
| Column | What goes in it | Notes |
|---|---|---|
| Country | Three-letter country code, e.g. GBR | * matches all countries |
| Region/State | Region code where applicable | Usually * for UK stores |
| Zip/Postal Code | Postcode or * | Matching is exact or wildcard — postcode ranges are one of the first places native runs out of road |
| Condition value | The threshold for your chosen condition (weight, subtotal or item count) and above | The condition type is fixed per website — every row uses the same one |
| Shipping Price | The rate charged for that band | One rate per row; the best match wins |
Whatever tool generates it, keep one spreadsheet as the source of truth, one row per destination band, explicit * wildcards rather than blank cells — and re-export after every import so the file you store matches what the store is actually serving.
Where native stops
The native carrier's constraints are structural, not bugs: exactly one table per website, exactly one condition type, one anonymous "Best Way" method at checkout, and no per-method free-shipping thresholds. The moment you need an economy table and an express table side by side, or a rate that depends on weight and subtotal, or free delivery over a threshold in mainland Britain but not the Highlands and Islands, you are past what it can express. This bites hardest for trade and B2B stores, where carrier contracts and negotiated delivery terms are part of the offer — the same gap that pushes distributors towards a proper B2B setup on Magento Open Source rather than workarounds.
Native vs an advanced table-rate engine
Our Shipping Matrix for Magento 2 module is an advanced table-rate engine that behaves like a normal carrier at checkout, on Luma or headless.
| Capability | Native table rates | Shipping Matrix |
|---|---|---|
| Tables per website | One | Multiple named methods, each with its own table and checkout title |
| Rate conditions | One of weight, subtotal or item count | Combinations — weight, subtotal, item count and destination together |
| Free-shipping thresholds | Separate carrier, all-or-nothing | Per method, so express can stay chargeable while economy goes free |
| CSV import/export | Per website, hidden at Default scope | Per method |
| Checkout presentation | One method title | Each method appears as its own option with its own name |
Test the edges before go-live
Shipping tables fail at boundaries, so that is where to test: the postcode band edges, the exact free-shipping threshold value, the heaviest cart you realistically sell, and a destination that should get no method at all. Do the testing through the storefront cart and checkout as a customer would, not by reading the CSV back — the file can be right while a scope, cache or currency setting makes checkout serve something else. And if you advertise on Google Shopping, remember Merchant Center expects the delivery cost a shopper sees at checkout to match what your product data promises — worth a pass over your Google Shopping feed whenever shipping rules change.
FAQ
Why can I not see the import and export buttons for table rates?
They only appear when the configuration scope is switched from Default Config to a specific website, using the scope selector on the configuration page. Native table rates are stored per website, so at Default scope there is nothing to import into.
Can native Magento combine weight and price in one table?
No. The native carrier uses exactly one condition type per website — weight, subtotal or item count, never a combination. Rates conditioned on more than one factor need an advanced table-rate module.
What does the asterisk mean in the table rates CSV?
It is a wildcard matching any value in that column — any country, region or postcode. Use it explicitly rather than leaving cells blank, and keep more specific rows for the destinations that need their own rate; the closest match wins.
Does table-rate shipping work with a headless storefront?
Yes. Rates are calculated server-side in Magento and returned to any checkout over GraphQL, so a headless frontend sees the same methods and prices as Luma. Built against Magento Open Source 2.4.9, running on PHP 8.4 and 8.5.
Shipping Matrix for Magento 2 is a one-off purchase — no subscription — and is included in the AgenticEcom Suite.
