---
title: "Persistent Storage"
description: "Configure persistent storage for build assets across deployments."
canonical_url: "https://nuxtseo.com/docs/skew-protection/guides/storage-configuration"
last_updated: "2026-05-25T17:23:14.224Z"
---

Nuxt Skew Protection needs persistent storage to preserve previous build assets across deployments.

By default, it uses the filesystem storage located at `node_modules/.cache/nuxt-seo/skew-protection`, but this may not be sufficient
for all deployment environments, especially in CI/CD pipelines where caches may be cleared frequently.

## Retention Periods

You can control how long versions are kept using [`retentionDays`](/docs/skew-protection/api/config#retentiondays-number) and [`maxNumberOfVersions`](/docs/skew-protection/api/config#maxnumberofversions-number). By default, the configuration is setup for optimal crawler compatibility.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  skewProtection: {
    // Keep versions for 45 days
    retentionDays: 45,
    // Keep maximum 15 versions
    maxNumberOfVersions: 15
  }
})
```

Cleanup happens **during build**, removing:

- Versions older than `retentionDays`
- Oldest versions beyond `maxNumberOfVersions`

## GitHub Actions

The default filesystem storage works with GitHub Actions caching to persist build assets between deployments
using the `actions/cache` GitHub Action.

<callout color="warning" icon="i-heroicons-exclamation-triangle">

The cache key must be unique per deployment, otherwise `actions/cache` won't save new assets (it only saves on cache miss).

</callout>

```yaml [your-github-workflow.yml]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Install...
      - name: Cache for Nuxt SEO
        uses: actions/cache@v4
        with:
          path: node_modules/.cache/nuxt-seo
          key: nuxt-skew-${{ github.sha }}
          restore-keys: |
            nuxt-skew-
      # Build, etc..
```

The `restore-keys` fallback ensures previous assets are restored, while the unique `github.sha` key ensures new assets are saved after each build.

## Cloudflare Deployment

If you have your deployments running through [Cloudflare](https://cloudflare.com) then the `node_modules` folder should automatically persist between deployments, so you do not need any additional configuration.

## Cloudflare KV

If you're deploying to Cloudflare using your own CI pipeline, you can use Cloudflare KV storage to persist build assets.

See the dedicated [Cloudflare Deployment](/docs/skew-protection/providers/cloudflare) guide which covers storage configuration in detail.

## Redis

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  skewProtection: {
    storage: {
      driver: 'redis',
      host: process.env.REDIS_HOST || 'localhost',
      port: Number(process.env.REDIS_PORT) || 6379,
      password: process.env.REDIS_PASSWORD,
      db: 0,
      base: 'skew-protection'
    }
  }
})
```

## Upstash Redis

For serverless deployments like [Netlify](https://netlify.com) or [Vercel](https://vercel.com), [Upstash](https://upstash.com/) provides a Redis-compatible database with an HTTP API.

Install the Upstash [Redis](https://redis.io) client:

```bash [Terminal]
npx nypm add @upstash/redis
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  skewProtection: {
    storage: {
      driver: 'upstash',
      url: process.env.UPSTASH_REDIS_REST_URL,
      token: process.env.UPSTASH_REDIS_REST_TOKEN,
      base: 'skew-protection'
    }
  }
})
```

You can find your REST URL and token in the [Upstash Console](https://console.upstash.com/) after creating a database.

## CDN Usage

In cases where you're already using a CDN with long cache times on `/_nuxt/**` assets, you may want to disable persistent storage using [`bundleAssets`](/docs/skew-protection/api/config#bundlepreviousdeploymentchunks-boolean).

```ts
export default defineNuxtConfig({
  skewProtection: {
    // Disable persistent storage
    bundleAssets: false
  }
})
```
