Skip to content

[deployment/web] Add --web-content-hash, Cache-Control, Overlay Deployment, and precache_manifest.json guidance for Flutter 3.50 #13825

Closed

Description

@kevmoo

Note

Target Release: Flutter 3.50 (Q4 2026 Stable)
All implementation phases for flutter build web --web-content-hash (Umbrella: flutter/flutter#149031) have landed for Flutter 3.50:

Page URL

Problem

With flutter build web --web-content-hash shipping in Flutter 3.50 (flutter/flutter#149031), the Flutter Web deployment and FAQ pages need to be updated (cc @parlough @sfshaza2):

  1. Outdated FAQ statement: sites/docs/src/content/platform-integration/web/faq.md#L180-L181 still states "Flutter doesn't currently support appending build IDs to resources automatically" and only shows the unhashed max-age=0, must-revalidate firebase.json rule (L197-L229).
  2. Missing --web-content-hash, Cache-Control, Overlay Deployment, and precache_manifest.json guidance: sites/docs/src/content/deployment/web.md does not yet document --web-content-hash, split Cache-Control rules for hashed vs. unhashed files, overlay deployments across releases, or custom service worker integration via precache_manifest.json.
Detailed page breakdown & affected targets (AI-assisted)

Proposed Content

1. sites/docs/src/content/platform-integration/web/faq.md (https://docs.flutter.dev/platform-integration/web/faq)

  • Replace L180-L181 ("Flutter doesn't currently support appending build IDs to resources automatically") with guidance on running flutter build web --web-content-hash, which automatically embeds 8-character truncated SHA-256 content hashes into compiled entrypoints (main.dart.<hash>.js, .wasm, .mjs), JS source maps (main.dart.<hash>.js.map, main.dart.<hash>.mjs.map when --source-maps is enabled), and 100% of files under build/web/assets/** (including AssetManifest.<hash>.bin, FontManifest.<hash>.json, NOTICES.<hash>, and shaders/**, with transparent runtime resolution in AssetManager and _flutter.buildConfig.extraAssets).
  • Under ### How do I configure my cache headers? (L183-L236), add the firebase.json configuration for --web-content-hash builds (matching the CLI tip in packages/flutter_tools/lib/src/commands/build_web.dart) that pairs max-age=0, must-revalidate on bootstrap files with public, max-age=31536000, immutable on hashed entrypoints and assets/**:
{
  "hosting": {
    "public": "build/web",
    "ignore": ["**/*.map"],
    "headers": [
      {
        "source": "**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=0, must-revalidate"
          }
        ]
      },
      {
        "source": "assets/**",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=31536000, immutable"
          }
        ]
      },
      {
        "source": "main.dart.*.+(js|wasm|mjs)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "public, max-age=31536000, immutable"
          }
        ]
      },
      {
        "source": "404.html",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=0, must-revalidate"
          }
        ]
      }
    ],
    "rewrites": [
      {
        "source": "!(/assets/**|/canvaskit/**|/icons/**|/main.dart.*)",
        "destination": "/index.html"
      }
    ]
  }
}

2. sites/docs/src/content/deployment/web.md (https://docs.flutter.dev/deployment/web)

Add a Web content hashing (--web-content-hash) section (with a :::version-note for Flutter 3.50+) covering:

  1. Hashed vs. Unhashed Build Outputs:
    • Immutable (public, max-age=31536000, immutable): main.dart.<hash>.js, main.dart.<hash>.wasm, main.dart.<hash>.mjs, main.dart.<hash>.js.map and main.dart.<hash>.mjs.map (if --source-maps is enabled and deployed), and all files under assets/** (including assets/AssetManifest.<hash>.bin, assets/AssetManifest.bin.<hash>.json, assets/FontManifest.<hash>.json, assets/NOTICES.<hash>, and assets/shaders/**).
    • Revalidate on Every Load (max-age=0, must-revalidate or no-cache): index.html, flutter_bootstrap.js, flutter.js, manifest.json, version.json, 404.html, canvaskit/** (when built with --no-web-resources-cdn), and main.dart.wasm.map (when built with --source-maps, since .wasm binaries embed an unhashed sourceMappingURL section).
  2. Overlay Deployments (Zero-Downtime Rollouts for Active Tabs):
    • When deploying a new release N, an already-open browser tab running release N-1 may lazily fetch an image, font, or asset with release N-1's content hash.
    • To prevent mid-session 404 errors during rollout, retain at least the previous release's (N-1) hashed entrypoints and assets/** files alongside the new release's (N) hashed files in your CDN/storage bucket (or prune old hashes after a 24–72 hour grace window) while atomically updating index.html and flutter_bootstrap.js.
  3. Custom Service Workers (build/web/precache_manifest.json):
    • When --web-content-hash is enabled, flutter build web generates build/web/precache_manifest.json ({"version": 1, "entries": [{"url": "...", "hash": "<8-char-sha256>", "size": ..., "urlHashed": true|false}]}) for consumption by custom PWA service workers or Workbox (where revision can be set to entry.urlHashed ? null : entry.hash).
  4. Current Limitations:
    • --web-content-hash does not yet support deferred imports (deferred as) in either JavaScript (dart2js) or WebAssembly (dart2wasm / --enable-wasm-deferred-loading) builds (flutter/flutter#191917).

3. sites/docs/src/content/platform-integration/web/initialization.md (https://docs.flutter.dev/platform-integration/web/initialization)

  • Note under ## Write a custom bootstrap script (L83-L103) that --web-content-hash injects the hashed entrypoint filenames (mainJsPath, jsSupportRuntimePath, mainWasmPath) and extraAssets (assetManifest, fontManifest, AssetManifest.bin, NOTICES, shaders/**) into {{flutter_build_config}}. Custom web/index.html or web/flutter_bootstrap.js files must use {{flutter_build_config}} with _flutter.loader.load() rather than hardcoding "main.dart.js" or calling the deprecated loadEntrypoint API.

Activity

  1. added
    p2-mediumNecessary but not urgent concern. Resolve when possible.
    st.blockedIssue cannot continue until another action completes
    act.await-dev-prNeeds dev PR to merge before merging docs
    dev.deploymentRelates to deploying Flutter app section of Flutter.dev
    target.webTarget apps on the web platform
    on Aug 27, 2026
  2. added a commit that references this issue on Aug 27, 2026
  3. uldall commented on Aug 28, 2026

    @uldall

    It would also be helpful to add documentation on how to handle new releases.

    IMHO the issue that needs handling is the following:

    • Client A downloads index.html (and flutter_bootstrap.js) which references main.dart.<hash>.js.
    • The server is updated with a new release of the Flutter application by deleting the files of the old release and adding the files of the new release.
    • Client A tries to download main.dart.<hash>.js, but the file no longer exists because the hash has changed in the new release.

    This problem also exists in a related manner even without the hash as files might have been updated between two releases, and now Client A will be downloading a "frankenstein" application that is a mixture of two releases.

    I believe this can potentially be solved by using --base-href and storing all previous releases of the application next to the new release. In this way index.html of Version X will only reference files in for example base /version-X/ and things should work fine. If I have understood things correctly, this however beats the purpose of the hash being added to files.

    Is the solution to blend all releases of the Flutter application into a single folder on the web server? I.e. such that main.dart.hash A.js exists next to main.dart.hash B.js?

  4. added
    p1-highMajor but not urgent concern: Resolve in months. Update each month.
    and removed
    p2-mediumNecessary but not urgent concern. Resolve when possible.
    st.blockedIssue cannot continue until another action completes
    act.await-dev-prNeeds dev PR to merge before merging docs
    on Oct 7, 2026
  5. changed the title [-][HOLD - Q4 Release] Add caching and Cache-Control header guidance to Web Deployment documentation[/-] [+][deployment/web] Add --web-content-hash, Cache-Control, Overlay Deployment, and precache_manifest.json guidance for Flutter 3.50[/+] on Oct 7, 2026
  6. added
    a.faqRelates to the FAQ section of Flutter.dev
    a.rn.release-notesRelates to Flutter release notes found on docs.flutter.dev
    on Oct 7, 2026
  7. added a commit that references this issue on Oct 25, 2026
    89e39d0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

a.faqRelates to the FAQ section of Flutter.deva.rn.release-notesRelates to Flutter release notes found on docs.flutter.devd.new-featureAdds new Flutter contentdev.deploymentRelates to deploying Flutter app section of Flutter.deve1-hoursEffort: < 8 hrsfrom.teamReported by Dash docs team memberp1-highMajor but not urgent concern: Resolve in months. Update each month.target.webTarget apps on the web platform

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions