> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cache images and small static files

> Cache CSS, JavaScript, fonts, and images on the edge while HTML pages and extensionless paths stay uncached.

## Customer Portal

When HTML pages and static files share the same CDN caching policy, visitors may receive outdated pages even though CSS, JavaScript, fonts, and images benefit from longer caching. Two CDN rules separate these behaviors, keeping pages uncached and static assets cached for four days.

A new CDN resource follows origin cache headers, with a four-day fallback when the origin sends none. That fallback applies to every file type, because [CDN caching](https://docs.gcore.com/cdn/cdn-resource-options/cache/specify-cache-lifetime-on-a-cdn-resource-or-origin.md) follows the status code and `Cache-Control`, not the extension.

![CDN caching set to Origin controlled with a four-day default](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/cdn-caching.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=9b7c89beb7a3618f77b24806aa38de5f)

Files with no requests for 36 hours leave the edge cache, whatever lifetime is set.

## Leave HTML uncached

With only that fallback, HTML is cached the same way as CSS. A rule sets `/`, any path ending in `.html`, and any path whose last segment has no dot to **Do not cache**.

1\. In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **CDN** > **CDN resources** and click the resource CNAME.

![CDN resources list filtered to one resource](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/cdn-resources-list.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=e9fa35e8445f6876dc15dfe09f49fa9a)

2\. Open the **Rules** tab. Click **Create rule**, then **Create blank rule**.

3\. Name the rule and enter `^/($|.*\.html$|[^./]+|.*/[^./]+)$`. The pattern is a regular expression and must start with `^/` or `/`.

The pattern covers the root path, `.html` files, and extensionless URLs. Adjust the pattern to match the website's URL structure.

![HTML rule name and pattern](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/html-rule-pattern.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=2479332758e4f4787e6e5881194e098b)

4\. Click **Add option**. Add **CDN caching**, set it to **CDN controlled**, and select **Do not cache**.

![HTML rule CDN caching set to Do not cache](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/html-rule-cdn-caching.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=977e77ec23881f08372a162d7d446715)

5\. Click **Create rule**.

The first matching rule wins, and this pattern does not overlap the static pattern below. A request for `/`, for `index.html`, or for a path whose last segment has no dot returns no `Cache` header, so the response is not stored.

## Cache the static files

CSS, JavaScript, fonts, and images need their own rule, because the resource fallback caches them the same way as HTML. Browser lifetime, query strings, compression, and CORS go on that same rule, and a resource allows five rules.

1\. On the **Rules** tab, click **Create rule**, then **Create blank rule**.

2\. Name the rule. Enter `^/.*\.(css|js|gif|png|jpe?g|webp|svg|ico|woff2?|ttf|otf|eot)$`.

![Static rule name and file-extension pattern](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-pattern.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=b50fd7b7833bedbf90698ab7daa3d462)

3\. Add **CDN caching**. Set **CDN controlled** and a lifetime of four days, the same length as the resource fallback.

![Static rule CDN caching set to four days](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-cdn-caching.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=65ac6945e1f13a0c3453e9da792371e8)

4\. Add **Browser caching** and set **CDN controlled** to 12 hours, shorter than the four-day edge lifetime. [Browser caching](https://docs.gcore.com/cdn/cdn-resource-options/cache/specify-cache-lifetime-for-user-browsers.md) sets that lifetime independently of the origin headers.

![Static rule browser caching set to 12 hours](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-browser-caching.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=c7ba2bb4dd73a8a58f8d0847482bf9d8)

5\. Add **Ignore query string** and select **Ignore all**, only when the query string does not change the file. The [query string](https://docs.gcore.com/cdn/cdn-resource-options/cache/ignore-the-set-cookie-or-query-string-parameters-when-caching-content-on-cdn-servers.md) article lists the other two modes.

![Static rule query string set to Ignore all](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-query-string.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=f3fdd4fd1146c968ddb611f1a402f4e8)

6\. Add **Gzip compression**.

![Static rule Gzip compression enabled](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-gzip.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=8bbf185ce7ab0a951ffe8cf5c14bd62e)

7\. Add **CORS header support**, because fonts loaded from another site need `Access-Control-Allow-Origin`. The [CORS header](https://docs.gcore.com/cdn/cdn-resource-options/http-headers/add-the-access-control-allow-origin-header-to-the-browser-response.md) article covers a star value and a specific origin.

![Static rule CORS set to any domain](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/static-rule-cors.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=65025d31a656a84b1c2eab98a328d304)

8\. Click **Create rule**.

![Rules tab with the HTML rule and the static rule active](https://mintcdn.com/gcore/u-P7ZBvVxyZ4SVf1/images/docs/cdn/cdn-resource-options/cache/cache-images-and-small-static-files/cdn-rules-list.png?fit=max\&auto=format\&n=u-P7ZBvVxyZ4SVf1\&q=85\&s=f33d9dfd31f22cf93e7d13d0765463c4)

The **Static content** template matches a much wider list, including archives and video. The pattern above stays on text, fonts, and images.

[Image Stack](https://docs.gcore.com/cdn/cdn-resource-options/image-optimization-paid/about-image-stack.md) transforms photos. Caching a JPEG does not require it.

## Publish a new file name

A new CSS, JavaScript, or image file goes out under a new URL, and `app.v2.css` is one name. The previous URL keeps serving its cached body, so that release does not need a purge.

When the bytes at an existing URL change, the edge keeps the previous body until that path is [purged](https://docs.gcore.com/cdn/clear-cdn-resource-cache-by-url-pattern-or-all.md). With **Ignore all** on, purging the path without the query string also clears the query variants, and a different file name stays cached.

## Check the response headers

Request the same URL twice and read `Cache`, `Cache-Control`, and `Content-Encoding`.

```bash theme={null}
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/index.html"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/about"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/static/app.css"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/static/app.css"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/static/app.css?build=1"
curl -sI -H "Accept-Encoding: gzip" "https://cdn.example.com/static/app.css?build=2"
curl -sI -H "Accept-Encoding: gzip" -H "Origin: https://example.com" "https://cdn.example.com/static/font.woff2"
```

A request for `/`, a path ending in `.html`, or a path whose last segment has no dot returns no `Cache` header. A second request for a CSS, font, or image file returns HIT, and `Cache-Control` carries the 12-hour browser lifetime.

Two query strings on the same CSS path share one cached object. A font requested with an `Origin` header returns `Access-Control-Allow-Origin`.

Gzip compresses a CSS file of 128 bytes or larger. A smaller CSS file, and a JPEG, are returned without `Content-Encoding`.

## REST API

Two rules split HTML from CSS, JavaScript, fonts, and images. The HTML rule disables the edge cache, and the static rule sets the edge lifetime, a shorter browser lifetime, query-string handling, Gzip, and CORS.

> [!NOTE]
>
> An [API token](https://docs.gcore.com/account-settings/api-tokens.md) is required. The resource ID comes from the [resources list](https://docs.gcore.com/api-reference/cdn/cdn-resources/list-cdn-resources).

```bash theme={null}
export GCORE_API_KEY="{YOUR_API_KEY}"
export CDN_RESOURCE_ID="{YOUR_CDN_RESOURCE_ID}"
```

A new resource leaves the edge lifetime origin-controlled, with a four-day fallback and an empty value field. Browser caching, Gzip, query strings, and CORS stay unset until a rule overrides that fallback.

Set `ruleType` to `0` for both rules. Rules are evaluated by ascending `weight`, and the first matching rule wins. A resource allows five rules.

## Leave HTML uncached

`value` `0s` is **Do not cache**. The pattern covers the root path, `.html` files, and extensionless URLs.

Adjust the pattern to match the website's URL structure.

> [tab] Python SDK
>
> ```python theme={null}
> import os
>
> from gcore import Gcore
>
> client = Gcore()
> resource_id = int(os.environ["CDN_RESOURCE_ID"])
>
> rule = client.cdn.cdn_resources.rules.create(
>     resource_id,
>     name="html-no-cache",
>     rule=r"^/($|.*\.html$|[^./]+|.*/[^./]+)$",
>     rule_type=0,
>     active=True,
>     weight=1,
>     options={
>         "edge_cache_settings": {"enabled": True, "value": "0s"},
>     },
> )
> print(rule.id, rule.rule)
> ```

> [tab] Go SDK
>
> ```go theme={null}
> package main
>
> import (
>     "context"
>     "fmt"
>     "os"
>     "strconv"
>
>     gcore "github.com/G-Core/gcore-go"
>     "github.com/G-Core/gcore-go/cdn"
> )
>
> func main() {
>     client := gcore.NewClient()
>     ctx := context.Background()
>     resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
>     if err != nil {
>         panic(err)
>     }
>
>     rule, err := client.CDN.CDNResources.Rules.New(ctx, resourceID, cdn.CDNResourceRuleNewParams{
>         Name:     "html-no-cache",
>         Rule:     `^/($|.*\.html$|[^./]+|.*/[^./]+)$`,
>         RuleType: 0,
>         Active:   gcore.Bool(true),
>         Weight:   gcore.Int(1),
>         Options: cdn.CDNResourceRuleNewParamsOptions{
>             EdgeCacheSettings: cdn.CDNResourceRuleNewParamsOptionsEdgeCacheSettings{
>                 Enabled: true,
>                 Value:   gcore.String("0s"),
>             },
>         },
>     })
>     if err != nil {
>         panic(err)
>     }
>     fmt.Println(rule.ID, rule.Rule)
> }
> ```

> [tab] curl
>
> ```bash theme={null}
> curl -X POST "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID/rules" \
>   -H "Authorization: APIKey $GCORE_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{
>     "name": "html-no-cache",
>     "rule": "^/($|.*\\.html$|[^./]+|.*/[^./]+)$",
>     "ruleType": 0,
>     "active": true,
>     "weight": 1,
>     "options": {
>       "edge_cache_settings": {"enabled": true, "value": "0s"}
>     }
>   }'
> ```

The API returns the rule, including `id` and `rule`. A later request for `/`, for `index.html`, or for a path whose last segment has no dot is not stored.

## Cache the static files

The edge lifetime is four days and does not follow origin headers, while the browser lifetime is 12 hours. Query strings are ignored only when the query string does not change the file.

Gzip is on, and CORS allows any origin. Replace `*` with the site origin when a font should stay limited to that site.

> [tab] Python SDK
>
> ```python theme={null}
> import os
>
> from gcore import Gcore
>
> client = Gcore()
> resource_id = int(os.environ["CDN_RESOURCE_ID"])
>
> rule = client.cdn.cdn_resources.rules.create(
>     resource_id,
>     name="static-assets",
>     rule=r"^/.*\.(css|js|gif|png|jpe?g|webp|svg|ico|woff2?|ttf|otf|eot)$",
>     rule_type=0,
>     active=True,
>     weight=2,
>     options={
>         "edge_cache_settings": {"enabled": True, "value": "4d"},
>         "browser_cache_settings": {"enabled": True, "value": "12h"},
>         "ignore_query_string": {"enabled": True, "value": True},
>         "gzipOn": {"enabled": True, "value": True},
>         "cors": {"enabled": True, "value": ["*"], "always": False},
>     },
> )
> print(rule.id, rule.rule)
> ```

> [tab] Go SDK
>
> ```go theme={null}
> package main
>
> import (
>     "context"
>     "fmt"
>     "os"
>     "strconv"
>
>     gcore "github.com/G-Core/gcore-go"
>     "github.com/G-Core/gcore-go/cdn"
> )
>
> func main() {
>     client := gcore.NewClient()
>     ctx := context.Background()
>     resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
>     if err != nil {
>         panic(err)
>     }
>
>     rule, err := client.CDN.CDNResources.Rules.New(ctx, resourceID, cdn.CDNResourceRuleNewParams{
>         Name:     "static-assets",
>         Rule:     `^/.*\.(css|js|gif|png|jpe?g|webp|svg|ico|woff2?|ttf|otf|eot)$`,
>         RuleType: 0,
>         Active:   gcore.Bool(true),
>         Weight:   gcore.Int(2),
>         Options: cdn.CDNResourceRuleNewParamsOptions{
>             EdgeCacheSettings: cdn.CDNResourceRuleNewParamsOptionsEdgeCacheSettings{
>                 Enabled: true,
>                 Value:   gcore.String("4d"),
>             },
>             BrowserCacheSettings: cdn.CDNResourceRuleNewParamsOptionsBrowserCacheSettings{
>                 Enabled: true,
>                 Value:   "12h",
>             },
>             IgnoreQueryString: cdn.CDNResourceRuleNewParamsOptionsIgnoreQueryString{
>                 Enabled: true,
>                 Value:   true,
>             },
>             GzipOn: cdn.CDNResourceRuleNewParamsOptionsGzipOn{
>                 Enabled: true,
>                 Value:   true,
>             },
>             Cors: cdn.CDNResourceRuleNewParamsOptionsCors{
>                 Enabled: true,
>                 Value:   []string{"*"},
>                 Always:  gcore.Bool(false),
>             },
>         },
>     })
>     if err != nil {
>         panic(err)
>     }
>     fmt.Println(rule.ID, rule.Rule)
> }
> ```

> [tab] curl
>
> ```bash theme={null}
> curl -X POST "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID/rules" \
>   -H "Authorization: APIKey $GCORE_API_KEY" \
>   -H "Content-Type: application/json" \
>   -d '{
>     "name": "static-assets",
>     "rule": "^/.*\\.(css|js|gif|png|jpe?g|webp|svg|ico|woff2?|ttf|otf|eot)$",
>     "ruleType": 0,
>     "active": true,
>     "weight": 2,
>     "options": {
>       "edge_cache_settings": {"enabled": true, "value": "4d"},
>       "browser_cache_settings": {"enabled": true, "value": "12h"},
>       "ignoreQueryString": {"enabled": true, "value": true},
>       "gzipOn": {"enabled": true, "value": true},
>       "cors": {"enabled": true, "value": ["*"], "always": false}
>     }
>   }'
> ```

The API returns the rule. A second request for a static file returns HIT, `Cache-Control` carries the 12-hour browser lifetime, and two query strings on that file share one object.

Gzip compresses a CSS file of 128 bytes or larger, while a JPEG is returned without `Content-Encoding`. A font requested with an `Origin` header returns `Access-Control-Allow-Origin`.

Publish the next CSS, JavaScript, or image file under a new URL, and [purge](https://docs.gcore.com/cdn/clear-cdn-resource-cache-by-url-pattern-or-all.md) an existing path only when its bytes change. That purge clears the query variants, and a different file name stays cached.
