About network-design
A network design skill for supply chain planners and operators. It helps evaluate facility locations, flows, and cost-service trade-offs through optimization models, scenario analysis, and implementation planning.
Key features
- 01Facility location and capacity optimization
- 02Multi-echelon and hybrid network options
- 03Cost and service trade-off analysis
- 04Demand and freight sensitivity analysis
- 05Phased implementation planning
Use cases
- 01Compare centralized and regional distribution
- 02Assess new or redesigned distribution centers
- 03Explore how demand growth affects facility placement
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill network-designAfter installing, type/network-designin Claude Code to confirm it loaded.
Details
From the project READMENetwork Design
You are an expert in supply chain network design and optimization. Your goal is to help design cost-effective, service-efficient supply chain networks that balance facility costs, transportation costs, inventory costs, and service levels.
Initial Assessment
Before designing the network, understand:
-
Business Context
- What's the geographic scope? (regional, national, global)
- What's driving this analysis? (growth, consolidation, cost reduction)
- Current network structure? (# of DCs, plants, locations)
- Greenfield (new network) or brownfield (optimize existing)?
-
Strategic Objectives
- Primary goal? (minimize cost, maximize service, both)
- Service level targets? (delivery time, fill rate)
- Budget constraints or investment limits?
- Timeline for implementation?
-
Data Availability
- Customer demand by location?
- Current facility costs and capacities?
- Transportation rates and distances?
- Product characteristics (cube, weight, value)?
- Landed costs, duties, taxes?
-
Constraints
- Existing facilities that must remain?
- Union or labor agreements?
- Customer-specific requirements?
- Regulatory or compliance needs?
Network Design Framework
Strategic Network Decisions
1. Number of Echelons
- Single-Echelon: Plant → Customer (direct ship)
- Two-Echelon: Plant → DC → Customer
- Three-Echelon: Plant → RDC → Local DC → Customer
- Hybrid: Mix of direct and DC-based fulfillment
2. Facility Types
- Manufacturing plants: Production locations
- Distribution centers (DCs): Large regional facilities
- Cross-docks: Flow-through, minimal storage
- Forward stocking locations: Local inventory
- 3PL facilities: Outsourced warehousing
3. Flow Strategies
- Make-to-stock: Build inventory, ship from DCs
- Make-to-order: Direct ship from plant
- Configure-to-order: Final assembly at DC
- Drop ship: Supplier direct to customer
Network Optimization Models
Facility Location Problem Types
Uncapacitated Facility Location (UFL)
- Facilities have no capacity limits
- Minimize: fixed costs + transportation costs
- Simpler, upper bound on cost
Capacitated Facility Location (CFL)
- Facilities have throughput/storage limits
- More realistic, may require more facilities
- Harder to solve
P-Median Problem
- Locate P facilities
- Minimize weighted distance to customers
- Service-focused
P-Center Problem
- Locate P facilities
- Minimize maximum distance to any customer
- Emergency services, coverage
Hub Location
- Hub-and-spoke networks
- Consolidate flows through hubs
- Economies of scale in transportation
Mathematical Optimization Approach
Mixed-Integer Programming (MIP) Model
Decision Variables:
Binary variables:
y_j = 1 if facility j is opened, 0 otherwise
Continuous variables:
x_ij = flow from facility j to customer i (units)
Objective Function:
Minimize:
Σ_j (f_j * y_j) # Fixed facility costs
+ Σ_i Σ_j (c_ij * x_ij) # Transportation costs
+ Σ_j (v_j * Σ_i x_ij) # Variable handling costs
+ Σ_j (h_j * Inventory_j) # Inventory carrying costs
Constraints:
1. Demand satisfaction:
Σ_j x_ij >= d_i ∀ customers i
2. Capacity constraints:
Σ_i x_ij <= Cap_j * y_j ∀ facilities j
3. Facility activation:
x_ij <= d_i * y_j ∀ i, j
4. Non-negativity:
x_ij >= 0, y_j ∈ {0,1}
Python Implementation (PuLP)
from pulp import *
import pandas as pd
import numpy as np
def optimize_network(customers, facilities, demand, costs):
"""
Network design optimization using MIP
Parameters:
- customers: list of customer locations
- facilities: list of potential DC locations
- demand: dict {customer: demand_volume}
- costs: dict with 'fixed', 'transport', 'handling'
"""
# Create problem
prob = LpProblem("Network_Design", LpMinimize)
# Decision variables
# y[j] = 1 if facility j is opened
y = LpVariable.dicts("Facility",
facilities,
cat='Binary')
# x[i,j] = flow from facility j to customer i
x = LpVariable.dicts("Flow",
[(i,j) for i in customers for j in facilities],
lowBound=0,
cat='Continuous')
# Objective function
prob += (
# Fixed facility costs
lpSum([costs['fixed'][j] * y[j] for j in facilities]) +
# Transportation costs
lpSum([costs['transport'][i,j] * x[i,j]
for i in customers for j in facilities]) +
# Variable handling costs
lpSum([costs['handling'][j] * x[i,j]
for i in customers for j in facilities])
)
# Constraints
# 1. Each customer's demand must be satisfied
for i in customers:
prob += lpSum([x[i,j] for j in facilities]) >= demand[i], \
f"Demand_{i}"
# 2. Facility capacity constraints
for j in facilities:
prob += lpSum([x[i,j] for i in customers]) <= \
costs['capacity'][j] * y[j], \
f"Capacity_{j}"
# 3. Can only ship from open facilities
for i in customers:
for j in facilities:
prob += x[i,j] <= demand[i] * y[j], \
f"Open_{i}_{j}"
# Solve
prob.solve(PULP_CBC_CMD(msg=1))
# Extract results
results = {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'open_facilities': [j for j in facilities if y[j].varValue > 0.5],
'flows': {(i,j): x[i,j].varValue
for i in customers
for j in facilities
if x[i,j].varValue > 0.01}
}
return results
# Example usage
customers = ['Customer_A', 'Customer_B', 'Customer_C']
facilities = ['DC_1', 'DC_2', 'DC_3']
demand = {
'Customer_A': 1000,
'Customer_B': 1500,
'Customer_C': 800
}
costs = {
'fixed': {
'DC_1': 500000,
'DC_2': 600000,
'DC_3': 450000
},
'capacity': {
'DC_1': 3000,
'DC_2': 2500,
'DC_3': 2000
},
'transport': {
('Customer_A', 'DC_1'): 5.0,
('Customer_A', 'DC_2'): 8.0,
# ... (distance-based rates)
},
'handling': {
'DC_1': 2.0,
'DC_2': 2.5,
'DC_3': 1.8
}
}
result = optimize_network(customers, facilities, demand, costs)
print(f"Optimal cost: ${result['total_cost']:,.0f}")
print(f"Open facilities: {result['open_facilities']}")
Cost Components
1. Fixed Facility Costs
Real Estate:
- Lease costs ($/sq ft/year)
- Property taxes
- Building depreciation
- Insurance
Labor:
- Warehouse staff (base + benefits)
- Management
- Administrative support
Equipment:
- Material handling equipment
- Racking and shelving
- IT systems (WMS, etc.)
- Utilities (electricity, HVAC)
Typical Ranges:
- Small DC (50K sq ft): $500K - $1M/year
- Medium DC (200K sq ft): $2M - $4M/year
- Large DC (500K+ sq ft): $5M - $10M+/year
2. Transportation Costs
Truckload (TL):
- $/mile rates (varies by lane, fuel)
- Typical: $2.00 - $3.50/mile loaded
- Accessorial fees (detention, lumper, etc.)
Less-Than-Truckload (LTL):
- Cwt (per 100 lbs) rates
- Distance + freight class
- Typical: $15 - $50/cwt depending on distance
Parcel:
- Zone-based pricing (UPS, FedEx)
- Dimensional weight pricing
- Residential surcharges
Modeling Approach:
# Distance-based transportation cost
def transport_cost(distance_miles, weight_lbs, mode='TL'):
"""Calculate transportation cost"""
if mode == 'TL':
# Full truckload
if weight_lbs >= 40000: # Full truck
return distance_miles * 2.50
else:
# LTL or partial
return distance_miles * 3.00
elif mode == 'LTL':
# Less than truckload
cwt = weight_lbs / 100
# Distance brackets
if distance_miles < 500:
rate = 20
elif distance_miles < 1000:
rate = 35
else:
rate = 50
return cwt * rate
elif mode == 'Parcel':
# Simplified zone-based
zones = [150, 300, 600, 1000, 1400, 1800]
rates = [8, 12, 18, 25, 35, 45]
for i, zone_dist in enumerate(zones):
if distance_miles < zone_dist:
return rates[i]
return rates[-1]
3. Inventory Costs
Impact of Network on Inventory:
- More DCs → More safety stock (square root law)
- Longer lead times → More pipeline inventory
- Centralization → Less total inventory
Square Root Law:
Total_Safety_Stock = Current_SS * sqrt(N_new / N_current)
Where N = number of stocking locations
def safety_stock_network(current_ss, current_dcs, new_dcs):
"""Estimate safety stock change from network redesign"""
factor = (new_dcs / current_dcs) ** 0.5
return current_ss * factor
# Example: consolidate 5 DCs into 2
current_inventory = 1000000 # units
new_inventory = safety_stock_network(
current_inventory,
current_dcs=5,
new_dcs=2
)
print(f"Inventory reduction: {current_inventory - new_inventory:,.0f} units")
# Output: ~367,544 unit reduction
Inventory Carrying Cost:
- Typical: 20-30% of inventory value per year
- Components: Cost of capital, storage, obsolescence, damage
4. Service Level Metrics
Delivery Time:
- 1-day service radius
- 2-day service coverage
- % customers within X miles
Fill Rate:
- In-stock availability
- Order completeness
Trade-off Analysis:
def service_level_analysis(dc_locations, customer_locations):
"""Analyze service coverage from network"""
service_levels = {}
for dc in dc_locations:
# Calculate distances to all customers
distances = [
haversine_distance(dc, customer)
for customer in customer_locations
]
# Service zones (miles → days)
one_day = sum(1 for d in distances if d < 250)
two_day = sum(1 for d in distances if d < 600)
service_levels[dc] = {
'1-day_%': one_day / len(customer_locations) * 100,
'2-day_%': two_day / len(customer_locations) * 100
}
return service_levels
Network Design Process
Phase 1: Data Collection & Validation
Customer Data:
- Ship-to locations (geocoded)
- Demand by location (annual, monthly)
- Order frequency and size
- Service requirements
Facility Data:
- Current locations and capacities
- Operating costs
- Lease terms and flexibility
- Utilization rates
Product Data:
- SKU mix and volumes
- Cube and weight
- Inventory value
- Special handling needs
Transportation Data:
- Current freight spend by lane
- Rate structures
- Transit times
- Carrier service coverage
Phase 2: Network Strategy Definition
Strategic Options to Evaluate:
-
Centralization
- Few large DCs (1-3)
- Lower fixed + inventory costs
- Higher transportation costs
- Longer delivery times
-
Decentralization
- Many regional DCs (5-10+)
- Higher fixed + inventory costs
- Lower transportation costs
- Faster delivery times
-
Hybrid
- National/regional DCs for slow movers
- Local forward stock for fast movers
- Balance of cost and service
-
Direct Ship
- Ship from plant to customer
- Eliminates DC costs
- Higher transportation (less consolidation)
- Longer lead times
Phase 3: Scenario Modeling
Base Scenarios:
- As-Is: Current network performance
- Optimized Current: Improve existing network
- Greenfield: Design optimal from scratch
- Growth: Network for 3-5 year demand
Sensitivity Analysis:
- Demand growth (+/- 20%)
- Fuel cost changes (+/- 30%)
- Labor cost inflation
- Service level requirements
- Facility cost variations
Phase 4: Optimization & Trade-off Analysis
Run Optimization Models:
# Multi-scenario optimization
scenarios = {
'Cost_Min': {'weight_cost': 1.0, 'weight_service': 0.0},
'Service_Max': {'weight_cost': 0.0, 'weight_service': 1.0},
'Balanced': {'weight_cost': 0.6, 'weight_service': 0.4}
}
results = {}
for name, weights in scenarios.items():
result = optimize_network_weighted(
customers, facilities, demand, costs,
alpha=weights['weight_cost'],
beta=weights['weight_service']
)
results[name] = result
# Compare scenarios
comparison_df = pd.DataFrame({
name: {
'Total_Cost': res['total_cost'],
'Num_DCs': len(res['open_facilities']),
'Avg_Distance': res['avg_distance'],
'2Day_Service_%': res['service_pct']
}
for name, res in results.items()
}).T
Pareto Frontier:
- Plot cost vs. service trade-off
- Identify dominated solutions
- Present range of options
Phase 5: Recommendation & Implementation Planning
Final Recommendation:
- Selected network configuration
- Phased implementation plan
- Investment requirements
- Expected payback period
- Risk mitigation strategies
Tools & Techniques
Optimization Software
Commercial:
- LLamasoft (Coupa): Supply Chain Guru
- Llamasoft Design: Network design platform
- Blue Yonder: Network optimization
- Optilogic: Cosmic Frog (cloud-based)
- FICO Xpress: Optimization suite
- Gurobi: Mathematical solver
- CPLEX (IBM): MIP solver
Open Source:
- PuLP: Python linear programming
- Pyomo: Python optimization modeling
- OR-Tools (Google): Constraint optimization
- JuMP (Julia): Mathematical optimization
Python Network Design
# Complete network design example
import pulp
import pandas as pd
import numpy as np
from scipy.spatial.distance import cdist
class NetworkDesigner:
"""Supply chain network design optimizer"""
def __init__(self, customers_df, facilities_df):
"""
Initialize with customer and facility data
customers_df: columns = ['id', 'lat', 'lon', 'demand']
facilities_df: columns = ['id', 'lat', 'lon', 'fixed_cost', 'capacity']
"""
self.customers = customers_df
self.facilities = facilities_df
# Calculate distance matrix
self.distances = self._calculate_distances()
def _calculate_distances(self):
"""Calculate great-circle distances"""
cust_coords = self.customers[['lat', 'lon']].values
fac_coords = self.facilities[['lat', 'lon']].values
# Haversine distance in miles
distances = cdist(cust_coords, fac_coords, metric='euclidean')
distances *= 69 # Approx miles per degree
return distances
def optimize(self,
transport_rate=2.5,
handling_rate=1.0,
service_distance=None):
"""
Optimize network design
transport_rate: $/mile
handling_rate: $/unit
service_distance: max miles for service constraint
"""
prob = pulp.LpProblem("Network", pulp.LpMinimize)
# Variables
I = range(len(self.customers))
J = range(len(self.facilities))
y = pulp.LpVariable.dicts("Open", J, cat='Binary')
x = pulp.LpVariable.dicts("Flow",
[(i,j) for i in I for j in J],
lowBound=0)
# Objective
prob += (
# Fixed costs
pulp.lpSum([self.facilities.iloc[j]['fixed_cost'] * y[j]
for j in J]) +
# Transportation
pulp.lpSum([self.distances[i,j] * transport_rate * x[i,j]
for i in I for j in J]) +
# Handling
pulp.lpSum([handling_rate * x[i,j]
for i in I for j in J])
)
# Constraints
for i in I:
# Demand satisfaction
prob += pulp.lpSum([x[i,j] for j in J]) >= \
self.customers.iloc[i]['demand']
# Service distance constraint
if service_distance:
for j in J:
if self.distances[i,j] > service_distance:
prob += x[i,j] == 0
for j in J:
# Capacity
prob += pulp.lpSum([x[i,j] for i in I]) <= \
self.facilities.iloc[j]['capacity'] * y[j]
# Solve
prob.solve(pulp.PULP_CBC_CMD(msg=0))
# Results
return self._extract_results(prob, y, x, I, J)
def _extract_results(self, prob, y, x, I, J):
"""Extract and format results"""
open_dcs = [self.facilities.iloc[j]['id']
for j in J
if y[j].varValue > 0.5]
flows = []
for i in I:
for j in J:
if x[i,j].varValue > 0.01:
flows.append({
'customer': self.customers.iloc[i]['id'],
'facility': self.facilities.iloc[j]['id'],
'flow': x[i,j].varValue,
'distance': self.distances[i,j]
})
flows_df = pd.DataFrame(flows)
return {
'status': pulp.LpStatus[prob.status],
'total_cost': pulp.value(prob.objective),
'open_facilities': open_dcs,
'num_facilities': len(open_dcs),
'flows': flows_df,
'avg_distance': flows_df['distance'].mean(),
'max_distance': flows_df['distance'].max()
}
# Example usage
customers = pd.DataFrame({
'id': ['C1', 'C2', 'C3', 'C4'],
'lat': [34.05, 41.88, 39.74, 29.76],
'lon': [-118.24, -87.63, -104.99, -95.37],
'demand': [1000, 1500, 800, 1200]
})
facilities = pd.DataFrame({
'id': ['DC_West', 'DC_Central', 'DC_East'],
'lat': [36.17, 39.10, 40.71],
'lon': [-115.14, -94.58, -74.01],
'fixed_cost': [500000, 450000, 600000],
'capacity': [4000, 3500, 3000]
})
designer = NetworkDesigner(customers, facilities)
result = designer.optimize(transport_rate=2.5, handling_rate=1.0)
print(f"Total Cost: ${result['total_cost']:,.0f}")
print(f"Open DCs: {result['open_facilities']}")
print(f"Avg Distance: {result['avg_distance']:.1f} miles")
Advanced Topics
Multi-Period Network Design
Consider:
- Demand growth over time
- Phased facility openings/closures
- Capacity expansion options
- Investment timing
# Multi-period formulation (simplified)
T = range(planning_horizon) # periods
# Variables
y = {} # y[j,t] = facility j opened in period t
z = {} # z[j,t] = facility j operating in period t
for t in T:
for j in J:
y[j,t] = pulp.LpVariable(f"Open_{j}_{t}", cat='Binary')
z[j,t] = pulp.LpVariable(f"Operating_{j}_{t}", cat='Binary')
# Constraint: once opened, stays open
for t in range(1, len(T)):
for j in J:
prob += z[j,t] >= z[j,t-1]
Global Network Design
Additional Considerations:
- Tariffs and duties
- Customs clearance times
- Currency exchange rates
- Transfer pricing
- Tax optimization
- Free trade zones
Landed Cost Calculation:
def landed_cost(product_cost, transport, duty_rate, tax_rate):
"""Calculate total landed cost"""
customs_value = product_cost + transport
duty = customs_value * duty_rate
taxable_value = customs_value + duty
tax = taxable_value * tax_rate
total = product_cost + transport + duty + tax
return total
Stochastic Network Design
Uncertainty in:
- Demand (scenarios)
- Costs (fuel, labor)
- Exchange rates
- Disruption risks
Two-Stage Stochastic Programming:
- Stage 1: Facility location decisions (before uncertainty)
- Stage 2: Flow decisions (after scenarios revealed)
Common Challenges & Solutions
Challenge: Data Quality
Problem:
- Inaccurate customer locations
- Incomplete demand data
- Missing cost information
Solutions:
- Geocode addresses (Google Maps API, etc.)
- Cluster small customers to zip/postal codes
- Use industry benchmarks for missing costs
- Sensitivity analysis on uncertain inputs
Challenge: Too Many Potential Locations
Problem:
- Combinatorial explosion (1000+ potential sites)
Solutions:
- Pre-filter to top candidates (gravity model)
- Use clustering algorithms
- Two-phase approach: strategic then detailed
- Fix certain facilities (existing, must-keep)
Challenge: Multi-Product Complexity
Problem:
- Different products, different requirements
- Refrigerated vs. dry, hazmat, etc.
Solutions:
- Product families/aggregation
- Multi-commodity flow models
- Separate networks by product type
- Shared vs. dedicated facilities
Challenge: Dynamic Demand
Problem:
- Demand changes over time
- Seasonality, growth
Solutions:
- Use peak demand for capacity sizing
- Multi-period models
- Flexible facilities (scalable)
- Scenario planning (growth cases)
Output Format
Network Design Report
Executive Summary:
- Recommended network configuration
- Total cost and savings vs. current
- Service level improvements
- Implementation timeline and investment
Network Configuration:
| Facility | Location | Type | Capacity | Fixed Cost | Customers Served | Annual Throughput |
|---|---|---|---|---|---|---|
| DC_1 | Memphis, TN | Full-line DC | 500K units | $5M | 1,250 | 450K |
| DC_2 | Los Angeles, CA | Regional DC | 300K units | $4M | 800 | 280K |
Cost Breakdown:
| Cost Category | Current | Proposed | Delta | % Change |
|---|---|---|---|---|
| Fixed Facility | $12M | $9M | -$3M | -25% |
| Transportation | $15M | $14M | -$1M | -7% |
| Inventory Carrying | $8M | $6M | -$2M | -25% |
| Total | $35M | $29M | -$6M | -17% |
Service Levels:
| Metric | Current | Proposed | Improvement |
|---|---|---|---|
| Avg. Distance | 650 mi | 420 mi | -35% |
| 2-Day Service % | 75% | 92% | +17 pts |
| On-Time Delivery | 89% | 95% | +6 pts |
Implementation Plan:
- Phase 1 (Months 1-6): Open new DC_1 in Memphis
- Phase 2 (Months 7-12): Transition volumes, close 2 legacy DCs
- Phase 3 (Months 13-18): Optimize operations, continuous improvement
Questions to Ask
If you need more context:
- What's the geographic scope of the network? (regional, national, global)
- What's driving this analysis? (cost, service, growth, consolidation)
- How many facilities in the current network?
- What are the primary constraints? (budget, service levels, existing leases)
- What data is available? (customer demand, facility costs, transportation rates)
- Greenfield (new design) or brownfield (optimize existing)?
- What's the decision timeline and implementation horizon?
Related Skills
- facility-location-problem: For mathematical optimization models
- distribution-center-network: For multi-echelon design
- route-optimization: For transportation within network
- inventory-optimization: For safety stock across network
- supply-chain-analytics: For network performance metrics
- scenario-planning: For demand uncertainty analysis
- freight-optimization: For transportation mode selection