Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Artisan Cloudflare Laravel Package

sebdesign/artisan-cloudflare

A Laravel package that adds Artisan commands for managing Cloudflare, so you can purge cache, manage DNS records, and control zones from the CLI or scheduled tasks. It wraps the Cloudflare API in a simple, configurable integration for your app.

View on GitHub
Deep Wiki
Context7

Getting Started

sebdesign/artisan-cloudflare is a thin Laravel wrapper around the Cloudflare API whose main job is to let you purge the Cloudflare edge cache from the CLI — so a deploy, a content publish, or a scheduled job can invalidate the CDN without anyone logging into the dashboard.

composer require sebdesign/artisan-cloudflare
php artisan vendor:publish --tag=cloudflare   # publishes config/cloudflare.php

Add credentials to .env (never to the config file):

[email protected]
CLOUDFLARE_KEY=your-global-api-key     # or CLOUDFLARE_API_TOKEN for scoped tokens
CLOUDFLARE_ZONE=your-zone-id

The first use case you should wire up is the one you'll use forever: purge everything at the end of a deploy.

php artisan cloudflare:purge

Verify it worked before building anything on top of it — run with -v to see the API response, then hard-refresh a static asset and confirm the cf-cache-status header flips from HIT to MISS. Run php artisan list cloudflare to see the exact command signatures and options for the installed version rather than trusting a blog post.

Version note (v2.9.0): this release adds Laravel 13.x support and drops PHP 7.x and Laravel 5.x. If any app is still on PHP 7.4 or Laravel 5.x, pin "sebdesign/artisan-cloudflare": "^2.8" in composer.json before running composer update, otherwise the solver will fail or, worse, you'll only discover it during a deploy.

Implementation Patterns

Deploy hook (the 90% case). Put the purge at the very end of your deploy script, after php artisan migrate and after caches are warmed, so you don't purge and then immediately re-warm stale data:

php artisan down --render="errors::503" || true
git pull && composer install --no-dev -o && php artisan migrate --force
php artisan config:cache && php artisan route:cache && php artisan view:cache
php artisan up
php artisan cloudflare:purge --quiet

Because purge-all is cheap to call but expensive for origin traffic, only run it on deploys that actually change publicly cacheable output — gate it on whether public/ or resources/ changed.

Selective URL purge. For content-driven sites, purging everything on every article edit is overkill. Prefer targeted purges driven from model events:

// app/Observers/ArticleObserver.php
public function saved(Article $article): void
{
    PurgeArticleCache::dispatch($article->url(), "/blog/{$article->slug}");
}

// app/Jobs/PurgeArticleCache.php
public function handle(): void
{
    Artisan::call('cloudflare:purge', [
        'urls' => $this->urls,   // confirm the argument name with `php artisan help cloudflare:purge`
    ]);
}

Always dispatch this on a queue — the Cloudflare call is an external HTTP round-trip and has no business blocking a save request. Use dispatchAfterResponse() for low-traffic sites where a queue worker is overkill.

Sitemap-driven sweeps. For a nightly "make sure the cache matches reality" job, iterate your sitemap and purge in batches. Cloudflare's single-URL purge endpoint accepts a limited number of files per call (30), so chunk:

collect($urls)->chunk(30)->each(fn ($chunk) => Artisan::call('cloudflare:purge', [
    'urls' => $chunk->all(),
]));

Programmatic use. Rather than shelling out, resolve the package's client/service from the container (check config/cloudflare.php and the service provider for the exact binding name in your version) when you need the return value or want to handle errors granularly. Reserve Artisan::call() for scripts and one-off jobs where the command output is the point.

Environment separation. Staging and production should never share a zone. Drive CLOUDFLARE_ZONE from the environment and add a guard in your deploy script so a misconfigured staging box can't nuke production's cache:

[ "$APP_ENV" = "production" ] || { echo "skipping purge"; exit 0; }

Gotchas and Tips

  • Zone ID, not domain. The most common misconfiguration is putting example.com in CLOUDFLARE_ZONE. Cloudflare's purge endpoints want the 32-char zone ID from the dashboard overview page. Symptom: a 400/Invalid zone identifier from the API.
  • Global API key vs. API token. Global keys need the account email alongside them; scoped API tokens do not and are strongly preferred. The token needs at minimum Zone → Cache Purge → Purge permission on the specific zone. A 403 almost always means missing permission, not a wrong key.
  • Purge ≠ browser cache. This only clears Cloudflare's edge. If you served Cache-Control: max-age=86400, users keep the stale copy. Pair purges with filename hashing (Mix/Vite already do this) or short browser TTLs.
  • Purge-all is not instantaneous worldwide. Propagation is usually sub-second but can lag a few seconds per PoP. Don't write a deploy script that purges and then immediately asserts on new content via a different edge location.
  • Rate limits. Purge-all has a per-zone call budget; aggressive loops (e.g. one purge per model save in a bulk import) will get you throttled. Batch, debounce, or queue-with-delay.
  • Tags and hostname purges are Enterprise-only. If you're planning a cache-tag strategy, verify your plan first — the command will fail on lower tiers.
  • Credential leakage in CI logs. Artisan::call() output and -v verbosity can echo request context. Use --quiet in CI and keep secrets in the platform's secret store (Forge/Vapor/GitHub Actions secrets), never in config/cloudflare.php.
  • Config caching. After changing CLOUDFLARE_*, run php artisan config:clear. A cached config from a previous deploy is the second most common "it says unauthorized but the key is right" cause.
  • Package auto-discovery. On Laravel 5.5+ this works out of the box; if you've disabled discovery or are on a hand-rolled skeleton, register Sebdesign\ArtisanCloudflare\CloudflareServiceProvider manually.
  • Debugging order of operations: (1) php artisan config:clear, (2) confirm env values with php artisan tinker --execute="dump(config('cloudflare'))", (3) hit the Cloudflare API directly with curl using the same token to isolate whether it's the credentials or the package, (4) re-run the command with -v.
  • Extension points are minimal by design. This package is a command wrapper, not an abstraction layer. If you need retries, circuit breaking, or structured logging, wrap the command in your own job/service and let the package stay dumb.
  • Upgrade path from 2.8 → 2.9.0 is a no-op for modern apps, but check composer.lock in CI: a transitive cloudflare/sdk bump can change exception types your error handling catches. Add a smoke test that runs the purge command against a throwaway zone.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console