diff --git a/database/factories/ItemFactory.php b/database/factories/ItemFactory.php
index 6c8fe2df..9a496a2a 100644
--- a/database/factories/ItemFactory.php
+++ b/database/factories/ItemFactory.php
@@ -33,7 +33,6 @@ public function modelName(): string
     public function definition(): array
     {
         return [
-            'tax' => mt_rand(10, 100),
             'name' => $this->faker->company(),
             'price' => mt_rand(10, 100),
             'quantity' => mt_rand(1, 10),
diff --git a/database/factories/ShippingFactory.php b/database/factories/ShippingFactory.php
index 7a151035..5148f22f 100644
--- a/database/factories/ShippingFactory.php
+++ b/database/factories/ShippingFactory.php
@@ -34,8 +34,7 @@ public function modelName(): string
     public function definition(): array
     {
         return [
-            'tax' => mt_rand(0, 20),
-            'cost' => mt_rand(0, 100),
+            'fee' => mt_rand(0, 100),
             'driver' => Manager::getDefaultDriver(),
         ];
     }
diff --git a/database/factories/TaxFactory.php b/database/factories/TaxFactory.php
new file mode 100644
index 00000000..e69de29b
diff --git a/database/factories/TaxRateFactory.php b/database/factories/TaxRateFactory.php
new file mode 100644
index 00000000..e69de29b
diff --git a/database/migrations/2020_01_01_000300_create_bazar_items_table.php b/database/migrations/2020_01_01_000300_create_bazar_items_table.php
index 51ce38c9..bfa0654c 100644
--- a/database/migrations/2020_01_01_000300_create_bazar_items_table.php
+++ b/database/migrations/2020_01_01_000300_create_bazar_items_table.php
@@ -17,7 +17,6 @@ public function up(): void
             $table->nullableMorphs('buyable');
             $table->string('name');
             $table->float('price')->unsigned();
-            $table->float('tax')->unsigned()->default(0);
             $table->float('quantity')->unsigned();
             $table->json('properties')->nullable();
             $table->timestamps();
diff --git a/database/migrations/2020_01_01_001000_create_bazar_shippings_table.php b/database/migrations/2020_01_01_001000_create_bazar_shippings_table.php
index 97843534..442c8711 100644
--- a/database/migrations/2020_01_01_001000_create_bazar_shippings_table.php
+++ b/database/migrations/2020_01_01_001000_create_bazar_shippings_table.php
@@ -15,8 +15,7 @@ public function up(): void
             $table->id();
             $table->morphs('shippable');
             $table->string('driver');
-            $table->float('cost')->unsigned()->default(0);
-            $table->float('tax')->unsigned()->default(0);
+            $table->float('fee')->unsigned()->default(0);
             $table->timestamps();
         });
     }
diff --git a/database/migrations/2024_07_28_082227_create_bazar_tax_rates_table.php b/database/migrations/2024_07_28_082227_create_bazar_tax_rates_table.php
index 1c12f5ab..6c583cb1 100644
--- a/database/migrations/2024_07_28_082227_create_bazar_tax_rates_table.php
+++ b/database/migrations/2024_07_28_082227_create_bazar_tax_rates_table.php
@@ -13,6 +13,8 @@ public function up(): void
     {
         Schema::create('bazar_tax_rates', static function (Blueprint $table): void {
             $table->id();
+            $table->integer('value')->unsigned();
+            $table->boolean('shipping')->default(false);
             $table->timestamps();
         });
     }
diff --git a/database/migrations/2024_07_28_082252_create_bazar_buyable_tax_rate_table.php b/database/migrations/2024_07_28_082252_create_bazar_buyable_tax_rate_table.php
index eaddfa89..4f776f00 100644
--- a/database/migrations/2024_07_28_082252_create_bazar_buyable_tax_rate_table.php
+++ b/database/migrations/2024_07_28_082252_create_bazar_buyable_tax_rate_table.php
@@ -13,6 +13,8 @@ public function up(): void
     {
         Schema::create('bazar_buyable_tax_rate', static function (Blueprint $table): void {
             $table->id();
+            $table->foreignId('tax_rate_id')->constrained('bazar_tax_rates')->cascadeOnDelete();
+            $table->morphs('buyable');
             $table->timestamps();
         });
     }
diff --git a/database/migrations/2024_07_28_082302_create_bazar_taxes_table.php b/database/migrations/2024_07_28_082302_create_bazar_taxes_table.php
index 4c5bf918..3e26a248 100644
--- a/database/migrations/2024_07_28_082302_create_bazar_taxes_table.php
+++ b/database/migrations/2024_07_28_082302_create_bazar_taxes_table.php
@@ -13,7 +13,12 @@ public function up(): void
     {
         Schema::create('bazar_taxes', static function (Blueprint $table): void {
             $table->id();
+            $table->foreignId('tax_rate_id')->nullable()->constrained('bazar_tax_rates')->nullOnDelete();
+            $table->morphs('taxable');
+            $table->float('value')->unsigned();
             $table->timestamps();
+
+            $table->unique(['taxable_id', 'taxable_type', 'tax_rate_id']);
         });
     }
 
diff --git a/src/BazarServiceProvider.php b/src/BazarServiceProvider.php
index 0cd4185a..4dc731f7 100644
--- a/src/BazarServiceProvider.php
+++ b/src/BazarServiceProvider.php
@@ -22,6 +22,8 @@ class BazarServiceProvider extends ServiceProvider
         Interfaces\Models\Property::class => Models\Property::class,
         Interfaces\Models\PropertyValue::class => Models\PropertyValue::class,
         Interfaces\Models\Shipping::class => Models\Shipping::class,
+        Interfaces\Models\Tax::class => Models\Tax::class,
+        Interfaces\Models\TaxRate::class => Models\TaxRate::class,
         Interfaces\Models\Transaction::class => Models\Transaction::class,
         Interfaces\Models\Variant::class => Models\Variant::class,
     ];
@@ -33,7 +35,6 @@ class BazarServiceProvider extends ServiceProvider
         Interfaces\Cart\Manager::class => Cart\Manager::class,
         Interfaces\Gateway\Manager::class => Gateway\Manager::class,
         Interfaces\Repositories\DiscountRepository::class => Repositories\DiscountRepository::class,
-        Interfaces\Repositories\TaxRepository::class => Repositories\TaxRepository::class,
         Interfaces\Shipping\Manager::class => Shipping\Manager::class,
     ];
 
diff --git a/src/Cart/Driver.php b/src/Cart/Driver.php
index 1bb1d5aa..d2ba0a91 100644
--- a/src/Cart/Driver.php
+++ b/src/Cart/Driver.php
@@ -69,8 +69,8 @@ public function getModel(): Cart
             if (! $cart->locked && $cart->currency !== Bazar::getCurrency()) {
                 $cart->setAttribute('currency', Bazar::getCurrency());
                 $cart->syncItems();
-                $cart->shipping->calculateCost(false);
-                $cart->shipping->calculateTax();
+                $cart->shipping->calculateFee();
+                $cart->shipping->calculateTaxes();
                 $cart->calculateDiscount();
             }
         });
@@ -147,7 +147,7 @@ public function removeItems(array $ids): void
     public function updateItem(string $id, array $properties = []): void
     {
         if ($item = $this->getItem($id)) {
-            $item->fill($properties)->calculateTax();
+            $item->fill($properties)->calculateTaxes();
 
             $this->sync();
         }
@@ -161,7 +161,7 @@ public function updateItems(array $data): void
         $items = $this->getItems()->whereIn('id', array_keys($data));
 
         $items->each(static function (Item $item) use ($data): void {
-            $item->fill($data[$item->getKey()])->calculateTax();
+            $item->fill($data[$item->getKey()])->calculateTaxes();
         });
 
         if ($items->isNotEmpty()) {
@@ -229,7 +229,7 @@ public function empty(): void
         $this->getModel()->items()->delete();
         $this->getModel()->setRelation('items', $this->getModel()->items()->getRelated()->newCollection());
 
-        $this->getShipping()->update(['tax' => 0, 'cost' => 0]);
+        $this->getShipping()->update(['tax' => 0, 'fee' => 0]);
 
         $this->getModel()->calculateDiscount();
     }
@@ -273,8 +273,10 @@ public function isNotEmpty(): bool
      */
     public function sync(): void
     {
-        $this->getShipping()->calculateCost(false);
-        $this->getShipping()->calculateTax();
+        $this->getShipping()->calculateFee();
+        $this->getShipping()->save();
+
+        $this->getShipping()->calculateTaxes();
 
         $this->getModel()->calculateDiscount();
     }
diff --git a/src/Interfaces/Buyable.php b/src/Interfaces/Buyable.php
index ecab40ea..0bd8eaae 100644
--- a/src/Interfaces/Buyable.php
+++ b/src/Interfaces/Buyable.php
@@ -3,6 +3,7 @@
 namespace Cone\Bazar\Interfaces;
 
 use Cone\Bazar\Models\Item;
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
 
 interface Buyable
 {
@@ -11,6 +12,11 @@ interface Buyable
      */
     public function buyable(Checkoutable $checkoutable): bool;
 
+    /**
+     * Get the tax rates for the variant.
+     */
+    public function taxRates(): MorphToMany;
+
     /**
      * Get the item representation of the buyable instance.
      */
diff --git a/src/Interfaces/Checkoutable.php b/src/Interfaces/Checkoutable.php
index 09e786a6..b5f09920 100644
--- a/src/Interfaces/Checkoutable.php
+++ b/src/Interfaces/Checkoutable.php
@@ -66,7 +66,7 @@ public function getFormattedTax(): string;
     /**
      * Calculate the tax.
      */
-    public function calculateTax(bool $update = true): float;
+    public function calculateTax(): float;
 
     /**
      * Find an item by its attributes or make a new instance.
diff --git a/src/Interfaces/Models/Shipping.php b/src/Interfaces/Models/Shipping.php
index c568b1b7..dddae7b2 100644
--- a/src/Interfaces/Models/Shipping.php
+++ b/src/Interfaces/Models/Shipping.php
@@ -13,7 +13,7 @@ interface Shipping extends LineItem
     public function shippable(): MorphTo;
 
     /**
-     * Calculate the cost.
+     * Calculate the fee.
      */
-    public function calculateCost(bool $update = true): float;
+    public function calculateFee(): float;
 }
diff --git a/src/Interfaces/Models/Tax.php b/src/Interfaces/Models/Tax.php
index 4d0f57cb..a59a5a26 100644
--- a/src/Interfaces/Models/Tax.php
+++ b/src/Interfaces/Models/Tax.php
@@ -2,7 +2,23 @@
 
 namespace Cone\Bazar\Interfaces\Models;
 
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\MorphTo;
+
 interface Tax
 {
-    //
+    /**
+     * Get the taxable model for the model.
+     */
+    public function taxable(): MorphTo;
+
+    /**
+     * Get the tax rate for the model.
+     */
+    public function taxRate(): BelongsTo;
+
+    /**
+     * Get the formatted tax.
+     */
+    public function format(): string;
 }
diff --git a/src/Interfaces/Models/Variant.php b/src/Interfaces/Models/Variant.php
index 28f1afba..9b690f77 100644
--- a/src/Interfaces/Models/Variant.php
+++ b/src/Interfaces/Models/Variant.php
@@ -11,22 +11,22 @@
 interface Variant extends Buyable, Stockable
 {
     /**
-     * Get the items for the product.
+     * Get the items for the variant.
      */
     public function items(): MorphMany;
 
     /**
-     * Get the orders for the product.
+     * Get the orders for the variant.
      */
     public function orders(): HasManyThrough;
 
     /**
-     * Get the carts for the product.
+     * Get the carts for the variant.
      */
     public function carts(): HasManyThrough;
 
     /**
-     * Get the product for the transaction.
+     * Get the product for the variant.
      */
     public function product(): BelongsTo;
 }
diff --git a/src/Interfaces/Tax.php b/src/Interfaces/Tax.php
deleted file mode 100644
index 4d112088..00000000
--- a/src/Interfaces/Tax.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-namespace Cone\Bazar\Interfaces;
-
-interface Tax
-{
-    /**
-     * Calculate the tax for the given model.
-     */
-    public function __invoke(Taxable $model): float;
-}
diff --git a/src/Interfaces/Taxable.php b/src/Interfaces/Taxable.php
index de32c88a..d745674b 100644
--- a/src/Interfaces/Taxable.php
+++ b/src/Interfaces/Taxable.php
@@ -2,30 +2,32 @@
 
 namespace Cone\Bazar\Interfaces;
 
+use Illuminate\Database\Eloquent\Relations\MorphMany;
+
 interface Taxable
 {
     /**
-     * Get the tax.
+     * Get the taxes for the model.
      */
-    public function getTax(): float;
+    public function taxes(): MorphMany;
 
     /**
-     * Get the formatted tax.
+     * Get the tax base.
      */
-    public function getFormattedTax(): string;
+    public function getTaxBase(): float;
 
     /**
-     * Get the tax rate.
+     * Get the tax total.
      */
-    public function getTaxRate(): float;
+    public function getTaxTotal(): float;
 
     /**
-     * Get the formatted tax rate.
+     * Get the formatted tax.
      */
-    public function getFormattedTaxRate(): string;
+    public function getFormattedTaxTotal(): string;
 
     /**
-     * Calculate the tax.
+     * Calculate the taxes.
      */
-    public function calculateTax(bool $update = true): float;
+    public function calculateTaxes(): float;
 }
diff --git a/src/Models/Item.php b/src/Models/Item.php
index c7a1b587..6bc267c5 100644
--- a/src/Models/Item.php
+++ b/src/Models/Item.php
@@ -14,7 +14,6 @@
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\MorphTo;
-use Illuminate\Support\Number;
 
 class Item extends Model implements Contract
 {
@@ -42,7 +41,6 @@ class Item extends Model implements Contract
         'price' => 0,
         'properties' => '[]',
         'quantity' => 1,
-        'tax' => 0,
     ];
 
     /**
@@ -54,7 +52,6 @@ class Item extends Model implements Contract
         'price' => 'float',
         'properties' => 'json',
         'quantity' => 'float',
-        'tax' => 'float',
     ];
 
     /**
@@ -69,7 +66,6 @@ class Item extends Model implements Contract
         'price',
         'properties',
         'quantity',
-        'tax',
     ];
 
     /**
@@ -148,7 +144,7 @@ protected function formattedPrice(): Attribute
     protected function total(): Attribute
     {
         return new Attribute(
-            get: fn (): float => $this->getTotal(),
+            get: fn (): float => $this->getTotal()
         );
     }
 
@@ -160,7 +156,7 @@ protected function total(): Attribute
     protected function formattedTotal(): Attribute
     {
         return new Attribute(
-            get: fn (): string => $this->getFormattedTotal(),
+            get: fn (): string => $this->getFormattedTotal()
         );
     }
 
@@ -172,7 +168,7 @@ protected function formattedTotal(): Attribute
     protected function subtotal(): Attribute
     {
         return new Attribute(
-            get: fn (): float => $this->getSubtotal(),
+            get: fn (): float => $this->getSubtotal()
         );
     }
 
@@ -184,7 +180,7 @@ protected function subtotal(): Attribute
     protected function formattedSubtotal(): Attribute
     {
         return new Attribute(
-            get: fn (): string => $this->getFormattedSubtotal(),
+            get: fn (): string => $this->getFormattedSubtotal()
         );
     }
 
@@ -217,7 +213,7 @@ public function getFormattedPrice(): string
      */
     public function getTotal(): float
     {
-        return ($this->getPrice() + $this->getTax()) * $this->getQuantity();
+        return ($this->getPrice() + $this->getTaxTotal()) * $this->getQuantity();
     }
 
     /**
@@ -245,19 +241,19 @@ public function getFormattedSubtotal(): string
     }
 
     /**
-     * Get the tax rate.
+     * Get the tax base.
      */
-    public function getTaxRate(): float
+    public function getTaxBase(): float
     {
-        return $this->getPrice() > 0 ? ($this->getTax() / $this->getPrice()) * 100 : 0;
+        return $this->price;
     }
 
     /**
-     * Get the formatted tax rate.
+     * Get the formatted tax.
      */
-    public function getFormattedTaxRate(): string
+    public function getFormattedTaxTotal(): string
     {
-        return Number::percentage($this->getTaxRate());
+        return (new Currency($this->getTaxTotal(), $this->checkoutable->getCurrency()))->format();
     }
 
     /**
@@ -283,4 +279,16 @@ public function isFee(): bool
     {
         return ! $this->isLineItem();
     }
+
+    /**
+     * Calculate the taxes.
+     */
+    public function calculateTaxes(): float
+    {
+        $this->buyable->taxRates->each(function (TaxRate $taxRate): void {
+            $taxRate->calculate($this);
+        });
+
+        return $this->getTaxTotal();
+    }
 }
diff --git a/src/Models/Product.php b/src/Models/Product.php
index 7bb1d5ed..12175bdb 100644
--- a/src/Models/Product.php
+++ b/src/Models/Product.php
@@ -18,6 +18,7 @@
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Database\Query\Builder as QueryBuilder;
 
@@ -91,10 +92,18 @@ public function variants(): HasMany
         return $this->hasMany(Variant::getProxiedClass());
     }
 
+    /**
+     * Get the tax rates.
+     */
+    public function taxRates(): MorphToMany
+    {
+        return $this->morphToMany(TaxRate::getProxiedClass(), 'buyable', 'bazar_buyable_tax_rate');
+    }
+
     /**
      * Determine whether the buyable object is available for the checkoutable instance.
      */
-    public function buyable(Checkoutable $checkoutable): bool
+    public function buyable(Checkoutable $model): bool
     {
         return true;
     }
diff --git a/src/Models/Shipping.php b/src/Models/Shipping.php
index 18986af5..9ca254e6 100644
--- a/src/Models/Shipping.php
+++ b/src/Models/Shipping.php
@@ -14,7 +14,6 @@
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\MorphTo;
-use Illuminate\Support\Number;
 use Throwable;
 
 class Shipping extends Model implements Contract
@@ -30,8 +29,7 @@ class Shipping extends Model implements Contract
      * @var array<string, mixed>
      */
     protected $attributes = [
-        'cost' => 0,
-        'tax' => 0,
+        'fee' => 0,
     ];
 
     /**
@@ -40,8 +38,7 @@ class Shipping extends Model implements Contract
      * @var array<string, string>
      */
     protected $casts = [
-        'cost' => 'float',
-        'tax' => 'float',
+        'fee' => 'float',
     ];
 
     /**
@@ -50,9 +47,8 @@ class Shipping extends Model implements Contract
      * @var list<string>
      */
     protected $fillable = [
-        'cost',
+        'fee',
         'driver',
-        'tax',
     ];
 
     /**
@@ -202,12 +198,20 @@ public function getName(): string
         return $this->driverName;
     }
 
+    /**
+     * Get the tax base.
+     */
+    public function getTaxBase(): float
+    {
+        return $this->fee;
+    }
+
     /**
      * Get the price.
      */
     public function getPrice(): float
     {
-        return $this->cost;
+        return $this->fee;
     }
 
     /**
@@ -223,7 +227,7 @@ public function getFormattedPrice(): string
      */
     public function getTotal(): float
     {
-        return $this->getPrice() + $this->getTax();
+        return $this->getPrice() + $this->getTaxTotal();
     }
 
     /**
@@ -251,19 +255,11 @@ public function getFormattedSubtotal(): string
     }
 
     /**
-     * Get the tax rate.
-     */
-    public function getTaxRate(): float
-    {
-        return $this->getPrice() > 0 ? ($this->getTax() / $this->getPrice()) * 100 : 0;
-    }
-
-    /**
-     * Get the formatted tax rate.
+     * Get the formatted tax total.
      */
-    public function getFormattedTaxRate(): string
+    public function getFormattedTaxTotal(): string
     {
-        return Number::percentage($this->getTaxRate());
+        return (new Currency($this->getTaxTotal(), $this->shippable->getCurrency()))->format();
     }
 
     /**
@@ -275,20 +271,30 @@ public function getQuantity(): float
     }
 
     /**
-     * Calculate the cost.
+     * Calculate the fee.
      */
-    public function calculateCost(bool $update = true): float
+    public function calculateFee(): float
     {
         try {
-            $this->cost = Manager::driver($this->driver)->calculate($this->shippable);
-
-            if ($update) {
-                $this->save();
-            }
+            $this->update([
+                'fee' => Manager::driver($this->driver)->calculate($this->shippable),
+            ]);
         } catch (Throwable $exception) {
             //
-        } finally {
-            return $this->cost;
         }
+
+        return $this->fee;
+    }
+
+    /**
+     * Calculate the taxes.
+     */
+    public function calculateTaxes(): float
+    {
+        TaxRate::proxy()->newQuery()->applicableForShipping()->cursor()->each(function (TaxRate $taxRate): void {
+            $taxRate->calculate($this);
+        });
+
+        return $this->getTaxTotal();
     }
 }
diff --git a/src/Models/Tax.php b/src/Models/Tax.php
index 5ab7ab68..28a99057 100644
--- a/src/Models/Tax.php
+++ b/src/Models/Tax.php
@@ -3,15 +3,53 @@
 namespace Cone\Bazar\Models;
 
 use Cone\Bazar\Interfaces\Models\Tax as Contract;
+use Cone\Bazar\Support\Currency;
 use Cone\Root\Traits\InteractsWithProxy;
+use Illuminate\Database\Eloquent\Casts\Attribute;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\MorphTo;
 
 class Tax extends Model implements Contract
 {
     use HasFactory;
     use InteractsWithProxy;
 
+    /**
+     * The attributes that should have default values.
+     *
+     * @var array<string, mixed>
+     */
+    protected $attributes = [
+        'value' => null,
+    ];
+
+    /**
+     * The attributes that should be cast to native types.
+     *
+     * @var array<string, string>
+     */
+    protected $casts = [
+        'value' => 'float',
+    ];
+
+    /**
+     * The attributes that are mass assignable.
+     *
+     * @var list<string>
+     */
+    protected $fillable = [
+        'value',
+    ];
+
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'bazar_taxes';
+
     /**
      * Get the proxied interface.
      */
@@ -19,4 +57,38 @@ public static function getProxiedInterface(): string
     {
         return Contract::class;
     }
+
+    /**
+     * Get the taxable model for the model.
+     */
+    public function taxable(): MorphTo
+    {
+        return $this->morphTo();
+    }
+
+    /**
+     * Get the tax rate for the model.
+     */
+    public function taxRate(): BelongsTo
+    {
+        return $this->belongsTo(TaxRate::getProxiedClass());
+    }
+
+    /**
+     * Get the formatted value attribute.
+     */
+    protected function formattedValue(): Attribute
+    {
+        return new Attribute(
+            get: fn (): string => $this->format()
+        );
+    }
+
+    /**
+     * Get the formatted tax.
+     */
+    public function format(): string
+    {
+        return (new Currency($this->value, $this->taxable?->checkoutable?->getCurrency()))->format();
+    }
 }
diff --git a/src/Models/TaxRate.php b/src/Models/TaxRate.php
index 7a76093a..fdc2fea9 100644
--- a/src/Models/TaxRate.php
+++ b/src/Models/TaxRate.php
@@ -3,7 +3,9 @@
 namespace Cone\Bazar\Models;
 
 use Cone\Bazar\Interfaces\Models\TaxRate as Contract;
+use Cone\Bazar\Interfaces\Taxable;
 use Cone\Root\Traits\InteractsWithProxy;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
@@ -12,6 +14,13 @@ class TaxRate extends Model implements Contract
     use HasFactory;
     use InteractsWithProxy;
 
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'bazar_tax_rates';
+
     /**
      * Get the proxied interface.
      */
@@ -19,4 +28,25 @@ public static function getProxiedInterface(): string
     {
         return Contract::class;
     }
+
+    /**
+     * Calculate the tax for the taxable model.
+     */
+    public function calculate(Taxable $taxable): Tax
+    {
+        $value = round($taxable->getTaxBase() * $this->rate, 2);
+
+        return $taxable->taxes()->updateOrCreate(
+            ['tax_rate_id' => $this->getKey()],
+            ['value' => $value]
+        );
+    }
+
+    /**
+     * Scope the query for the results that are applicable for shipping.
+     */
+    public function scopeApplicableForShipping(Builder $query): Builder
+    {
+        return $query->where($query->qualifyColumn('shipping'), true);
+    }
 }
diff --git a/src/Models/Variant.php b/src/Models/Variant.php
index 3d2cb18b..c4599a77 100644
--- a/src/Models/Variant.php
+++ b/src/Models/Variant.php
@@ -17,6 +17,7 @@
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 class Variant extends Model implements Contract
@@ -83,6 +84,14 @@ public function product(): BelongsTo
             ->withDefault();
     }
 
+    /**
+     * Get the tax rates.
+     */
+    public function taxRates(): MorphToMany
+    {
+        return $this->morphToMany(TaxRate::getProxiedClass(), 'buyable', 'bazar_buyable_tax_rate');
+    }
+
     /**
      * Get the name attribute.
      *
diff --git a/src/Repositories/TaxRepository.php b/src/Repositories/TaxRepository.php
deleted file mode 100644
index 956b98ad..00000000
--- a/src/Repositories/TaxRepository.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-namespace Cone\Bazar\Repositories;
-
-use Closure;
-use Cone\Bazar\Interfaces\Repositories\TaxRepository as Contract;
-use Cone\Bazar\Interfaces\Tax;
-use Cone\Bazar\Interfaces\Taxable;
-
-class TaxRepository extends Repository implements Contract
-{
-    /**
-     * Determine if the taxes are disabled.
-     */
-    protected bool $disabled = false;
-
-    /**
-     * Register a new tax.
-     */
-    public function register(string $name, int|float|Closure|Tax $tax): void
-    {
-        $this->items->put($name, $tax);
-    }
-
-    /**
-     * Disable the tax calculation.
-     */
-    public function disable(): void
-    {
-        $this->disabled = true;
-    }
-
-    /**
-     * Enable the tax calculation.
-     */
-    public function enable(): void
-    {
-        $this->disabled = false;
-    }
-
-    /**
-     * Calculate tax for the given item.
-     */
-    public function calculate(Taxable $model): float
-    {
-        return $this->disabled
-            ? $model->tax
-            : $this->items->sum(function (int|float|Closure|Tax $tax) use ($model): float {
-                return $this->process($model, $tax);
-            });
-    }
-
-    /**
-     * Process the calculation.
-     */
-    protected function process(Taxable $model, int|float|Closure|Tax $tax): float
-    {
-        if (is_numeric($tax)) {
-            return $tax;
-        }
-
-        if ($tax instanceof Closure) {
-            return call_user_func_array($tax, [$model]);
-        }
-
-        if ($tax instanceof Tax) {
-            return call_user_func_array([$tax, '__invoke'], [$model]);
-        }
-
-        return 0;
-    }
-}
diff --git a/src/Shipping/Driver.php b/src/Shipping/Driver.php
index b0e6f2cd..46a82276 100644
--- a/src/Shipping/Driver.php
+++ b/src/Shipping/Driver.php
@@ -8,7 +8,7 @@
 abstract class Driver extends BaseDriver
 {
     /**
-     * Calculate the shipping cost.
+     * Calculate the shipping fee.
      */
     abstract public function calculate(Shippable $model): float;
 }
diff --git a/src/Shipping/LocalPickupDriver.php b/src/Shipping/LocalPickupDriver.php
index 4e78318b..4361208e 100644
--- a/src/Shipping/LocalPickupDriver.php
+++ b/src/Shipping/LocalPickupDriver.php
@@ -7,7 +7,7 @@
 class LocalPickupDriver extends Driver
 {
     /**
-     * Calculate the shipping cost.
+     * Calculate the shipping fee.
      */
     public function calculate(Shippable $model): float
     {
diff --git a/src/Support/Facades/Tax.php b/src/Support/Facades/Tax.php
deleted file mode 100644
index 8bf30fd9..00000000
--- a/src/Support/Facades/Tax.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Cone\Bazar\Support\Facades;
-
-use Cone\Bazar\Interfaces\Repositories\TaxRepository;
-use Illuminate\Support\Facades\Facade;
-
-/**
- * @method static void register(string $name, int|callable $tax)
- * @method static void remove(string $name)
- * @method static void disable()
- * @method static void enable()
- * @method static float calculate(\Cone\Bazar\Interfaces\Taxable $model)
- *
- * @see \Cone\Bazar\Interfaces\Repositories\TaxRepository
- */
-class Tax extends Facade
-{
-    /**
-     * Get the registered name of the component.
-     */
-    protected static function getFacadeAccessor(): string
-    {
-        return TaxRepository::class;
-    }
-}
diff --git a/src/Traits/InteractsWithItems.php b/src/Traits/InteractsWithItems.php
index 70edbff9..9c9e20d1 100644
--- a/src/Traits/InteractsWithItems.php
+++ b/src/Traits/InteractsWithItems.php
@@ -290,7 +290,7 @@ public function getFormattedFeeTotal(): string
     public function getTax(): float
     {
         $value = $this->taxables->sum(static function (LineItem $item): float {
-            return $item->getTax() * $item->getQuantity();
+            return $item->getTaxTotal() * $item->getQuantity();
         });
 
         return round($value, 2);
@@ -307,10 +307,10 @@ public function getFormattedTax(): string
     /**
      * Calculate the tax.
      */
-    public function calculateTax(bool $update = true): float
+    public function calculateTax(): float
     {
-        return $this->taxables->sum(static function (LineItem $item) use ($update): float {
-            return $item->calculateTax($update) * $item->getQuantity();
+        return $this->taxables->sum(static function (LineItem $item): float {
+            return $item->calculateTaxes() * $item->getQuantity();
         });
     }
 
@@ -365,7 +365,7 @@ public function syncItems(): void
             if ($item->isLineItem() && ! is_null($item->checkoutable)) {
                 $data = $item->buyable->toItem($item->checkoutable, $item->only('properties'))->only('price');
 
-                $item->fill($data)->calculateTax();
+                $item->fill($data)->calculateTaxes();
             }
         });
     }
diff --git a/src/Traits/InteractsWithTaxes.php b/src/Traits/InteractsWithTaxes.php
index d146028b..989c626b 100644
--- a/src/Traits/InteractsWithTaxes.php
+++ b/src/Traits/InteractsWithTaxes.php
@@ -2,64 +2,49 @@
 
 namespace Cone\Bazar\Traits;
 
-use Cone\Bazar\Bazar;
-use Cone\Bazar\Models\Item;
-use Cone\Bazar\Models\Shipping;
-use Cone\Bazar\Support\Currency;
-use Cone\Bazar\Support\Facades\Tax;
+use Cone\Bazar\Models\Tax;
 use Illuminate\Database\Eloquent\Casts\Attribute;
+use Illuminate\Database\Eloquent\Relations\MorphMany;
 
 trait InteractsWithTaxes
 {
     /**
-     * Get the formatted tax attribute.
-     *
-     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
+     * Get the taxes for the model.
      */
-    protected function formattedTax(): Attribute
+    public function taxes(): MorphMany
     {
-        return new Attribute(
-            get: fn (): string => $this->getFormattedTax()
-        );
+        return $this->morphMany(Tax::getProxiedClass(), 'taxable');
     }
 
     /**
-     * Get the tax.
+     * Get the tax total.
+     *
+     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
      */
-    public function getTax(): float
+    protected function taxTotal(): Attribute
     {
-        return $this->tax;
+        return new Attribute(
+            get: fn (): float => $this->getTaxTotal()
+        );
     }
 
     /**
-     * Get the formatted tax.
+     * Get the formatted tax attribute.
+     *
+     * @return \Illuminate\Database\Eloquent\Casts\Attribute<string, never>
      */
-    public function getFormattedTax(): string
+    protected function formattedTaxTotal(): Attribute
     {
-        $currency = Bazar::getCurrency();
-
-        if ($this instanceof Item) {
-            $currency = $this->checkoutable->currency;
-        }
-
-        if ($this instanceof Shipping) {
-            $currency = $this->shippable->currency;
-        }
-
-        return (new Currency($this->getTax(), $currency))->format();
+        return new Attribute(
+            get: fn (): string => $this->getFormattedTaxTotal()
+        );
     }
 
     /**
-     * Calculate the tax.
+     * Get the tax total.
      */
-    public function calculateTax(bool $update = true): float
+    public function getTaxTotal(): float
     {
-        $this->tax = Tax::calculate($this);
-
-        if ($update) {
-            $this->save();
-        }
-
-        return $this->tax;
+        return $this->taxes->sum('value');
     }
 }
diff --git a/tests/Models/ItemTest.php b/tests/Models/ItemTest.php
index 708de7ed..a8fd1a73 100644
--- a/tests/Models/ItemTest.php
+++ b/tests/Models/ItemTest.php
@@ -7,7 +7,6 @@
 use Cone\Bazar\Models\Item;
 use Cone\Bazar\Models\Product;
 use Cone\Bazar\Support\Currency;
-use Cone\Bazar\Support\Facades\Tax;
 use Cone\Bazar\Tests\TestCase;
 
 class ItemTest extends TestCase
@@ -18,10 +17,6 @@ public function setUp(): void
     {
         parent::setUp();
 
-        Tax::register('fix-10%', function (Taxable $item) {
-            return $item->price * 0.1;
-        });
-
         $cart = Cart::factory()->create();
         $product = Product::factory()->create();
 
@@ -36,10 +31,10 @@ public function test_item_is_taxable(): void
     {
         $this->assertInstanceOf(Taxable::class, $this->item);
         $this->assertSame(
-            (new Currency($this->item->tax, $this->item->checkoutable->currency))->format(),
-            $this->item->getFormattedTax()
+            (new Currency($this->item->getTaxTotal(), $this->item->checkoutable->currency))->format(),
+            $this->item->getFormattedTaxTotal()
         );
-        $this->assertSame($this->item->getFormattedTax(), $this->item->formattedTax);
+        $this->assertSame($this->item->getFormattedTaxTotal(), $this->item->formattedTaxTotal);
     }
 
     public function test_item_has_price_attribute(): void
diff --git a/tests/Models/ProductTest.php b/tests/Models/ProductTest.php
index 65554bff..8276fb15 100644
--- a/tests/Models/ProductTest.php
+++ b/tests/Models/ProductTest.php
@@ -35,7 +35,6 @@ public function test_product_has_many_orders_through_items(): void
 
         $item = Item::factory()->make([
             'price' => 100,
-            'tax' => 0,
             'quantity' => 3,
             'name' => $this->product->name,
         ])->checkoutable()->associate($order);
@@ -51,7 +50,6 @@ public function test_product_belongs_to_carts(): void
 
         $item = Item::factory()->make([
             'price' => 100,
-            'tax' => 0,
             'quantity' => 3,
             'name' => $this->product->name,
         ])->checkoutable()->associate($cart);
diff --git a/tests/Models/ShippingTest.php b/tests/Models/ShippingTest.php
index c72d8956..9524b063 100644
--- a/tests/Models/ShippingTest.php
+++ b/tests/Models/ShippingTest.php
@@ -2,14 +2,12 @@
 
 namespace Cone\Bazar\Tests\Models;
 
-use Cone\Bazar\Interfaces\Taxable;
 use Cone\Bazar\Models\Address;
 use Cone\Bazar\Models\Cart;
 use Cone\Bazar\Models\Order;
 use Cone\Bazar\Models\Shipping;
 use Cone\Bazar\Support\Currency;
 use Cone\Bazar\Support\Facades\Shipping as ShippingManager;
-use Cone\Bazar\Support\Facades\Tax;
 use Cone\Bazar\Tests\TestCase;
 use Cone\Bazar\Tests\User;
 
@@ -25,10 +23,6 @@ public function setUp(): void
     {
         parent::setUp();
 
-        Tax::register('fix-10%', function (Taxable $item) {
-            return $item->price * 0.1;
-        });
-
         $this->user = User::factory()->create();
         $this->cart = Cart::factory()->create();
         $this->shipping = Shipping::factory()->make();
@@ -75,29 +69,21 @@ public function test_shipping_has_address(): void
         $this->assertSame($address->id, $shipping->address->id);
     }
 
-    public function testt_can_calculate_calculateCost(): void
+    public function test_shipping_can_calculate_fee(): void
     {
-        $cost = $this->shipping->calculateCost();
-        $this->assertSame($cost, $this->shipping->cost);
+        $fee = $this->shipping->calculateFee();
+        $this->assertSame($fee, $this->shipping->fee);
     }
 
-    public function testt_is_taxable(): void
+    public function test_shipping_is_taxable(): void
     {
-        $this->shipping->calculateTax();
-
-        $this->assertInstanceOf(Taxable::class, $this->shipping);
-        $this->assertSame($this->shipping->price * 0.1, $this->shipping->tax);
-        $this->assertSame(
-            (new Currency($this->shipping->tax, $this->shipping->shippable->currency))->format(),
-            $this->shipping->getFormattedTax()
-        );
-        $this->assertSame($this->shipping->getFormattedTax(), $this->shipping->formattedTax);
+        $this->assertSame($this->shipping->getFormattedTaxTotal(), $this->shipping->formattedTaxTotal);
     }
 
     public function testt_has_total_attribute(): void
     {
         $this->assertSame(
-            $this->shipping->cost + $this->shipping->tax,
+            $this->shipping->fee + $this->shipping->tax,
             $this->shipping->getTotal()
         );
         $this->assertSame($this->shipping->getTotal(), $this->shipping->total);
@@ -106,7 +92,7 @@ public function testt_has_total_attribute(): void
             $this->shipping->getFormattedTotal()
         );
         $this->assertSame($this->shipping->getFormattedTotal(), $this->shipping->formattedTotal);
-        $this->assertSame($this->shipping->cost, $this->shipping->getSubtotal());
+        $this->assertSame($this->shipping->fee, $this->shipping->getSubtotal());
         $this->assertSame($this->shipping->getSubtotal(), $this->shipping->subtotal);
         $this->assertSame(
             (new Currency($this->shipping->subtotal, $this->shipping->shippable->currency))->format(),
diff --git a/tests/Repositories/TaxTest.php b/tests/Repositories/TaxTest.php
deleted file mode 100644
index d0b1d414..00000000
--- a/tests/Repositories/TaxTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-namespace Cone\Bazar\Tests\Repositories;
-
-use Cone\Bazar\Interfaces\Tax as Contract;
-use Cone\Bazar\Interfaces\Taxable;
-use Cone\Bazar\Models\Cart;
-use Cone\Bazar\Models\Product;
-use Cone\Bazar\Models\Shipping;
-use Cone\Bazar\Support\Facades\Tax;
-use Cone\Bazar\Tests\TestCase;
-
-class TaxTest extends TestCase
-{
-    protected Cart $cart;
-
-    public function setUp(): void
-    {
-        parent::setUp();
-
-        $this->cart = Cart::factory()->create();
-
-        Product::factory()->count(2)->create()->each(function ($product) {
-            $this->cart->items()->create([
-                'buyable_id' => $product->id,
-                'buyable_type' => Product::class,
-                'price' => $product->price,
-                'tax' => 0,
-                'quantity' => 1,
-                'name' => $product->name,
-            ]);
-        });
-
-        Tax::register('custom-30', 30);
-    }
-
-    public function test_tax_repository_calculates_taxes(): void
-    {
-        Tax::register('custom-object', new CustomTax);
-        Tax::register('custom-closure', function (Taxable $model) {
-            return $model instanceof Shipping ? 20 : 30;
-        });
-
-        $this->assertEquals(470, $this->cart->calculateTax());
-    }
-
-    public function test_tax_repository_removes_taxes(): void
-    {
-        Tax::remove('custom-30');
-
-        $this->assertEquals(0, $this->cart->calculateTax());
-    }
-
-    public function test_tax_repository_disables_taxes(): void
-    {
-        $this->assertEquals(90, $this->cart->calculateTax());
-
-        Tax::disable();
-
-        Tax::register('custom-10', 10);
-
-        $this->assertEquals(90, $this->cart->calculateTax());
-
-        Tax::enable();
-
-        $this->assertEquals(120, $this->cart->calculateTax());
-    }
-}
-
-class CustomTax implements Contract
-{
-    public function __invoke(Taxable $model): float
-    {
-        return 100;
-    }
-}