Release Flutter Web S3
Scope
Use this skill from the root of a Flutter application repository that publishes its Web build to AWS S3 or an S3-compatible object storage provider such as Cloudflare R2, MinIO, Tigris, Backblaze B2, or DigitalOcean Spaces.
Default assumptions:
- Version source:
pubspec.yaml - Build output:
build/web - Main entry point: this skill's
scripts/release_web_s3.py - Version helper: this skill's
scripts/prepare_web_release.py - Local deploy config:
deploy/s3.env, ignored by git - Default tag pattern:
web-v<pubspec version> - Package manager/runtime preference:
uvfor Python helpers,fvmwhen the project uses FVM - Fingerprinted live deploys are enabled by default via
FINGERPRINT_WEB_BUILD=1
Adapt these defaults to the target project before publishing. Do not assume the project has Slang, a specific GitHub Actions workflow, or a specific object storage provider.
Do not print secret values from deploy/s3.env or GitHub secrets. Any compatibility switch such as BUILD_WASM, FINGERPRINT_WEB_BUILD, S3_ADDRESSING_STYLE, AWS_REQUEST_CHECKSUM_CALCULATION, AWS_RESPONSE_CHECKSUM_VALIDATION, or ALLOW_DIRTY must be explicitly called out before use because these can hide provider or runtime differences.
Main Usage
Use scripts/release_web_s3.py as the only release entry point.
Parameters
--project-root: manually specify the Flutter project root; by default the script auto-detects it from git orpubspec.yaml--pubspec: override thepubspec.yamlpath relative to the project root--tag-match: specify the git tag glob used to locate the previous Web release; defaultweb-v*--tag-prefix: specify the git tag prefix for the new release; defaultweb-v--version: explicitly set the release version and bypass the suggested version--bump {major|minor|patch}: override the detected semantic version bump--dry-run: print planned file, git, build, and S3 actions without making changes--skip-tests: skip the Flutter test step during validation--no-tag: do not create the git release tag after publishing--no-push: do not push the git release tag to remote--yes/-y: non-interactive mode; fail instead of prompting for confirmation--promote <release-id>: skip version/build flow and promote an existing immutable release to the live prefix
Workflow Covered By The Script
The script handles the whole fixed flow automatically:
Preflight
- check git status and branch state
- verify Flutter Web project structure
- detect
fvm/flutter/dart - ensure
deploy/s3.envexists - verify S3 connectivity
Version
- inspect commits since the latest matching tag
- suggest a SemVer bump
- optionally accept an explicit or overridden version
- write the chosen version back to
pubspec.yaml
Validate
- run
flutter pub get - run
build_runnerif needed - run
slangif needed - run tests unless
--skip-tests - perform an S3 upload dry-run
- run
Publish
- build Flutter Web
- write
build/web/version.json - fingerprint cacheable build artifacts when enabled
- upload immutable release assets
- refresh live assets
- create and optionally push a git tag
Promote
- copy an existing immutable release to the live prefix without rebuilding
Configuration
Create deploy/s3.env.example with non-secret placeholders, then create a local deploy/s3.env from it and ensure deploy/s3.env is git-ignored.
Example:
S3_ENDPOINT_URL=https://s3.example.com
S3_BUCKET=my-bucket
S3_REGION=auto
S3_LIVE_PREFIX=web
S3_RELEASE_PREFIX=web/releases
BASE_HREF=/
PWA_STRATEGY=none
# AWS_PROFILE=my-profile
Required runtime configuration:
S3_ENDPOINT_URL: provider endpoint URLS3_BUCKET: target bucket- credentials via
AWS_PROFILE, CI secrets, or the provider's supported AWS CLI mechanism - for local uploads, prefer configuring a named AWS CLI profile with
aws configure --profile <new-profile-name>and settingAWS_PROFILE=<profile>
Optional project configuration:
S3_REGION: region passed to AWS CLI; defaultautoS3_LIVE_PREFIX: live object prefix; defaultwebS3_RELEASE_PREFIX: immutable release prefix; defaultweb/releasesBASE_HREF: passed toflutter build web --base-hrefPWA_STRATEGY: passed toflutter build web --pwa-strategyBUILD_WEB_DIR: override when the web output is notbuild/webBUILD_WASM=1: add--wasm, only after browser/runtime compatibility is verifiedFINGERPRINT_WEB_BUILD=1: rewrite cacheable web artifacts to content-hashed paths and emitbuild/web_fingerprint_manifest.jsonFLUTTER_CMD,DART_CMD: override command discovery for non-standard projectsPRE_BUILD_CMD,BUILD_RUNNER_CMD,SLANG_CMD,TEST_CMD: override build/test/codegen commandsRELEASE_CACHE_CONTROL,LIVE_CACHE_CONTROL,LIVE_STATIC_CACHE_CONTROL,LIVE_HASHED_CACHE_CONTROL: customize cache headers for uploaded assets
Fingerprint Mode
When FINGERPRINT_WEB_BUILD=1, the skill fingerprints cacheable build artifacts and rewrites references across the Flutter Web output so the live prefix can safely serve:
- stable entrypoints with short cache
- hashed assets with long immutable cache
Current stable entrypoints:
index.htmlflutter.jsflutter_service_worker.jsassets/AssetManifest.binassets/NOTICES
Current hashed targets include:
flutter_bootstrap.jsmanifest.jsonfavicon.pngversion.jsonmain.dart.jsmain.dart.mjsmain.dart.wasmicons/**assets/**except the stable files listed abovecanvaskit/**as one hashed directory prefix
The fingerprint pass also emits build/web_fingerprint_manifest.json. The release script uses this manifest to split live uploads into:
LIVE_CACHE_CONTROLfor stable filesLIVE_HASHED_CACHE_CONTROLfor hashed files
Recommended live cache policy when fingerprinting is enabled:
LIVE_CACHE_CONTROL=no-cache, no-store, must-revalidate
LIVE_HASHED_CACHE_CONTROL=public,max-age=31536000,immutable
Supported Flutter Output Assumptions
The fingerprint helper is intentionally coupled to current Flutter Web build structure. Before sharing this skill across projects, assume it needs review whenever Flutter changes its web output conventions.
This skill currently expects all of the following to exist in build/web after flutter build web:
index.htmlflutter_bootstrap.jsmain.dart.jsmain.dart.mjsmain.dart.wasmmanifest.jsonassets/AssetManifest.bin.jsonassets/FontManifest.jsoncanvaskit/
If a target project uses a different Flutter version or custom post-processing that changes these filenames or removes these files, re-verify the skill before reuse.
Project-Specific App Code
This skill does not inject application-level migration logic into shared projects. If a project needs one-time cleanup for old service workers or legacy browser caches, keep that logic in the project repo, not in the shared skill.
Version Helper
If you only need to inspect or write the version without running the full release flow, use prepare_web_release.py directly.
It can:
- inspect the current version from
pubspec.yaml - find the latest matching git tag
- inspect commits since the last release
- suggest a SemVer bump
- generate a tag name from the selected version
- optionally write the version back to
pubspec.yaml
Known Issues
S3_RELEASE_PREFIX as a sub-path of S3_LIVE_PREFIX
When S3_RELEASE_PREFIX is a child path of S3_LIVE_PREFIX (for example LIVE_PREFIX=web, RELEASE_PREFIX=web/releases), a naive live sync can accidentally delete immutable releases.
Symptom: after publishing, older immutable releases under web/releases/<version>/ are missing their files.
Fix: release_web_s3.py explicitly excludes releases/** during live sync and live refresh operations. The script also warns when it detects nested prefix configuration.
Flutter Web Output Drift
The fingerprint helper rewrites generated Flutter artifacts, not source templates. A Flutter SDK upgrade can change:
- bootstrap structure
- runtime asset lookup paths
- manifest formats
- canvaskit/skwasm layout
After upgrading Flutter in any project that uses this skill, rebuild once and run the fingerprint verifier before publishing.
Verification
For a shared-skill smoke test after flutter build web, run:
uv run python .agents/skills/release-flutter-web-s3/scripts/fingerprint_web_build.py build/web --manifest-out build/web_fingerprint_manifest.json
uv run python .agents/skills/release-flutter-web-s3/scripts/verify_fingerprint_web_build.py build/web --manifest build/web_fingerprint_manifest.json
Resources
scripts/
release_web_s3.py: main release entry point; handles versioning, validation, upload, publish, and promotefingerprint_web_build.py: fingerprint cacheable Flutter Web output files and rewrite internal referencesverify_fingerprint_web_build.py: verify that a fingerprinted Flutter Web build is internally consistentprepare_web_release.py: inspect commits since the latestweb-v*tag, suggest a SemVer version, generateweb-v<version>, draft release notes, and optionally updatepubspec.yamlreferences/awscli-setup.md: local setup guide for installing AWS CLI, obtainingak/sk, creating a named profile, and using that profile withrelease_web_s3.py