4.0 KiB
Best Practices
1. Use Selective Worker-First Routing
Instead of run_worker_first = true, use array patterns:
{
"assets": {
"run_worker_first": [
"/api/*", // API routes
"/admin/*", // Admin area
"!/admin/assets/*" // Except admin assets
]
}
}
Benefits:
- Reduces Worker invocations
- Lowers costs
- Improves asset delivery performance
2. Leverage Navigation Request Optimization
For SPAs, use compatibility_date = "2025-04-01" or later:
{
"compatibility_date": "2025-04-01",
"assets": {
"not_found_handling": "single-page-application"
}
}
Navigation requests skip Worker invocation, reducing costs.
3. Type Safety with Bindings
Always type your environment:
interface Env {
ASSETS: Fetcher;
}
Common Errors
"Asset not found"
Cause: Asset not in assets directory, wrong path, or assets not deployed
Solution: Verify asset exists, check path case-sensitivity, redeploy if needed
"Worker not invoked for asset"
Cause: Asset served directly, run_worker_first not configured
Solution: Configure run_worker_first patterns to include asset routes (see configuration.md:66-106)
"429 Too Many Requests on free tier"
Cause: run_worker_first patterns invoke Worker for many requests, hitting free tier limits (100k req/day)
Solution: Use more selective patterns with negative exclusions, or upgrade to paid plan
"Smart Placement increases latency"
Cause: run_worker_first=true + Smart Placement routes all requests through single smart-placed location
Solution: Use selective patterns (array syntax) or disable Smart Placement for asset-heavy apps
"CF-Cache-Status header unreliable"
Cause: Header is probabilistically added for privacy reasons
Solution: Don't rely on CF-Cache-Status for critical routing logic. Use other signals (ETag, age).
"JWT expired during deployment"
Cause: Large asset deployments exceed JWT token lifetime
Solution: Update to Wrangler 4.34.0+ (automatic token refresh), or reduce asset count
"Cannot use 'assets' with 'site'"
Cause: Legacy site config conflicts with new assets config
Solution: Migrate from site to assets (see configuration.md). Remove site key from wrangler.jsonc.
"Assets not updating after deployment"
Cause: Browser or CDN cache serving old assets
Solution:
- Hard refresh browser (Cmd+Shift+R / Ctrl+F5)
- Use cache-busting (hashed filenames)
- Verify deployment completed:
wrangler tail
Limits
| Resource/Limit | Free | Paid | Notes |
|---|---|---|---|
| Max asset size | 25 MiB | 25 MiB | Per file |
| Total assets | 20,000 | 100,000 | Requires Wrangler 4.34.0+ (Sep 2025) |
| Worker invocations | 100k/day | 10M/month | Optimize with run_worker_first patterns |
| Asset storage | Unlimited | Unlimited | Included |
Version Requirements
| Feature | Minimum Wrangler Version |
|---|---|
| 100k file limit (paid) | 4.34.0 |
| Vite plugin | 4.0.0 + @cloudflare/vite-plugin 1.0.0 |
| Navigation optimization | 4.0.0 + compatibility_date: "2025-04-01" |
Performance Tips
1. Use Hashed Filenames
Enable long-term caching with content-hashed filenames:
app.a3b2c1d4.js
styles.e5f6g7h8.css
Most bundlers (Vite, Webpack, Parcel) do this automatically.
2. Minimize Worker Invocations
Serve assets directly when possible:
{
"assets": {
// Only invoke Worker for dynamic routes
"run_worker_first": ["/api/*", "/auth/*"]
}
}
3. Leverage Browser Cache
Set appropriate Cache-Control headers:
// Versioned assets
'Cache-Control': 'public, max-age=31536000, immutable'
// HTML (revalidate often)
'Cache-Control': 'public, max-age=0, must-revalidate'
See patterns.md:169-189 for implementation.
4. Use .assetsignore
Reduce upload time by excluding unnecessary files:
*.map
*.md
.DS_Store
node_modules/
See configuration.md:107-126 for details.