
Building Microfrontends and Microservices in Turborepo on AWS

Stewart Moreland
Executive summary
A single monorepo can successfully host both microfrontends (MFEs) and microservices if (a) the repo structure makes ownership boundaries explicit, (b) your build system (Turborepo) is configured for deterministic caching and change-scoped execution, and (c) deployment contracts treat each MFE/service as independently releasable artifacts—even when code lives together. Turborepo's task graph, cacheable outputs, remote caching (including artifact signing), and strict environment-variable controls provide the mechanics for incremental builds and safe CI [1].
For MFEs on AWS, the most operationally stable default is static asset delivery via S3 + CloudFront with Origin Access Control (OAC) to keep buckets private, path-based CloudFront behaviors per MFE, and versioned asset paths to avoid frequent invalidations [2]. Client-side composition typically uses a shell that loads MFEs at runtime from either (1) a manifest/import map endpoint or (2) Module Federation remoteEntry.js coordinates. AWS Prescriptive Guidance explicitly describes a manifest-based discovery service and positions Module Federation and single-spa as common CSR composition tools [3].
For services, a pragmatic portfolio approach reduces risk: deploy "spiky / event-driven / low-ops" workloads to Lambda, deploy "steady-state / latency-sensitive / dependency-heavy" services to ECS (often on Fargate), and use EKS when you need Kubernetes ecosystem features and can justify its baseline control-plane cost and operational overhead. Canary and rollback controls should be "native" for each runtime: CloudFront staging/continuous deployment policies for CDN config changes, Lambda weighted aliases for function canaries, and ECS blue/green deployments for containerized services [4].
React 19 adds server-oriented capabilities (Server Components and Server Functions) and modern streaming SSR APIs (renderToReadableStream), but how these features integrate into a microfrontend build/composition approach is often framework/bundler-dependent; treat cross-MFE RSC composition details as unspecified unless your chosen framework explicitly supports it in an MFE setting [5].
Reference architecture for a combined monorepo
A combined MFE + microservice monorepo works best when you separate three planes:
- Build plane: Turborepo tasks (build/test/lint/deploy) with cacheable outputs, remote cache, and strict env rules [1].
- Delivery plane: CloudFront as the single global entry point for web delivery; S3 for static MFEs; optional origins for SSR/BFF; API origins for services.
- Runtime plane: Lambda/API Gateway (serverless), ECS/ALB (containers), EKS (Kubernetes).
Deployment topology diagram
CloudFront supports multiple origins, and each cache behavior maps to a single origin (or origin group). Plan your path patterns so each MFE/service "front door" is unambiguous and cacheable.
Table: single vs multiple CloudFront distributions for MFEs
| Decision | Single distribution (path-based behaviors) | Multiple distributions (per-MFE or per-domain) |
|---|---|---|
| Team autonomy | Medium: shared CloudFront config changes require coordination | High: teams can change caching/headers/origins independently |
| Blast radius | Larger: misconfiguration affects all MFEs | Smaller: changes isolated to one distribution |
| Routing model | Simpler: one domain, consistent cookies/auth | More complex: cross-domain cookies/CORS and DNS sprawl |
| TLS/DNS overhead | Lower: fewer certs/domains to manage | Higher: each distribution needs cert + DNS |
| CDN config canary | Strong: use CloudFront staging + continuous deployment policy | Per-distribution canary; more moving parts overall |
| Operational cost | Usually lower | Usually higher (more distributions, logs, policies, monitoring) |
CloudFront continuous deployment uses a primary distribution plus a staging distribution and routes a portion of traffic based on weight or headers, which is easier to operate when you have fewer distributions [4].
Monorepo layout and Turborepo configuration
Repo layout blueprint and ownership boundaries
A practical layout makes "what is deployable" obvious:
Use Turborepo Boundaries (tags + rules) to enforce "MFEs don't import each other" and to constrain which shared packages are allowed. This prevents accidental "federated monolith" coupling as the repo grows [1].
Turborepo task graph: minimal production-grade turbo.json
Key rules from the Turborepo docs:
- Task outputs must be declared if you want tasks to be cached and restored [1].
- Use
cache: falsefor side-effect tasks (like deployment) so they do not restore from cache artifacts. - If a task needs to respect dependency changes, configure
dependsOnappropriately; otherwise you can get incorrect cache hits (e.g., typechecking an app without noticing a breaking change in a shared UI package).
Example turbo.json (root):
{"$schema": "https://turborepo.dev/schema.json","envMode": "strict","globalDependencies": [".npmrc", "pnpm-lock.yaml"],"globalEnv": ["NODE_ENV"],"tasks": {"lint": {},"check-types": {"dependsOn": ["^check-types"]},"test": {"dependsOn": ["^build"]},"build": {"dependsOn": ["^build"],"outputs": ["dist/**", "build/**", ".next/**"]},"deploy": {"dependsOn": ["^build"],"cache": false},"dev": {"persistent": true,"cache": false}}}
Environment Variable Determinism
Strict environment mode filters env vars to those declared in env/globalEnv/passThroughEnv/globalPassThroughEnv, and Turborepo explicitly warns that missing env configuration can cause builds to reuse cache across environments incorrectly [1].
Incremental builds: change-scoped execution in dev and CI
Turborepo's --filter supports selecting packages by name, directory, or Git ranges/commits (including "dependents" selection via ...). This is the core primitive for "build only what changed" in a monorepo.
Examples you can standardize in docs/scripts:
# Build only MFEs changed since the previous committurbo run build --filter={./apps/*}[HEAD^1]# Build everything that depends on changes in a branch (useful for PR validation)turbo run build --filter=...[origin/my-feature]# Deploy only one MFE (and its dependencies) in CIturbo run deploy --filter=apps/mfe-catalog
This approach pairs naturally with Turborepo's CI guidance: rely on caching and targeted filters rather than building the whole repo on every change [1].
Remote caching: performance and integrity controls
Remote Caching
Remote caching is the difference between "monorepo is slow" and "monorepo is fast." Turborepo documents a turbo login + turbo link flow to enable remote caching across machines and CI. For supply-chain safety, Turborepo can sign remote-cache artifacts using HMAC-SHA256 and verify integrity/authenticity on download; invalid signatures are treated as cache misses [1].
Container builds: turbo prune --docker for minimal build contexts
Use turbo prune --docker to create a partial monorepo slice containing only the target and its internal dependencies and a pruned lockfile, arranged for Docker layer caching. This is the monorepo-native alternative to copying the entire repo into each Docker build.
Microfrontend implementation and S3 + CloudFront delivery
Composition contracts: manifest vs import maps vs Module Federation
A production MFE platform needs a discovery mechanism ("what MFEs exist and where are their artifacts?") and a runtime composition mechanism ("how does the shell load them?").
Manifest-based discovery (recommended baseline) AWS Prescriptive Guidance describes a manifest that contains micro-frontend metadata (name, URL, version, fallback behavior) served by a "discovery service" and queried by the shell after load [3]. In a monorepo, this manifest is also the cleanest place to encode release decisions ("catalog v1.8.2 + checkout v2.3.0").
Import maps (web-native mapping layer)
Import maps were incorporated into the HTML standard; they map module specifiers to URLs and can act as a vendor-neutral composition tool. In practice, you host importmap.json behind CloudFront, and the shell loads it before importing MFEs.
Module Federation (code-sharing + runtime remotes)
Webpack Module Federation explicitly supports consuming modules from independent builds at runtime. For MFEs in React, a standard approach is to share react and react-dom as singletons to avoid double-React issues; version constraints live in your federation config and build process.
Because AWS guidance lists Module Federation as a common choice for CSR MFEs, and because it provides a ready "remoteEntry" contract, it's often the fastest path to operational MFEs—provided you accept the coupling to Webpack (or compatible tooling) [3].
Project templates: shell and MFE packages
A practical set of templates should standardize:
basePath(e.g.,/mfe-catalog/) to align app router, asset routing, and CloudFront behaviors.- Build output structure (e.g.,
dist/). - Deployment contract (publish versioned artifacts, update manifest pointer).
- Interop boundary: exported
mount(el, props)function or route component exports.
Example "remote MFE" export contract (framework-agnostic, works with Module Federation or dynamic import):
// apps/mfe-catalog/src/mount.tsimport { createRoot } from "react-dom/client";import App from "./App";export function mount(el: HTMLElement, props: { basePath: string }) {const root = createRoot(el);root.render(<App basePath={props.basePath} />);return () => root.unmount();}
React 19 specifics: this pattern is unaffected by React 19 features; however, if you plan to use Server Components/Server Functions in MFEs, confirm your framework/bundler's support for these features across independently deployed artifacts (often unspecified in MFE contexts) [5].
Routing and CloudFront behavior mapping
Rule: browser routing must be consistent with CDN routing.
For SPA MFEs served from S3, CloudFront Functions can rewrite "directory-like" or extensionless URLs to index.html. AWS provides an official example that adds index.html to URIs missing file names/extensions.
CloudFront Function (viewer request) — scoped to one MFE base path:
async function handler(event) {var request = event.requestvar uri = request.uriif (!uri.startsWith('/mfe-catalog/')) return requestif (uri.endsWith('/')) {request.uri += 'index.html'} else if (!uri.includes('.')) {request.uri += '/index.html'}return request}
CloudFront Functions are explicitly designed for lightweight, high-scale URL rewrites, header manipulation, and cache-key normalization; use Lambda@Edge when you need heavier compute, third-party libraries, network access, or request body access.
CloudFront custom error responses can also be used to map certain origin errors to custom pages and response codes, but for multi-origin / multi-MFE setups, viewer-request rewrites are usually more precise and avoid "accidentally masking" true 404s for missing assets.
Deploying MFEs to S3 + CloudFront with OAC
Use OAC for S3 Origins
CloudFront recommends Origin Access Control (OAC) over legacy OAI for S3 origins. The CloudFront docs provide example S3 bucket policies that grant CloudFront read access using the CloudFront service principal with a SourceArn condition bound to a specific distribution. Use a regular S3 bucket (not an S3 website endpoint) and "always sign requests" for secure HTTPS communication between CloudFront and S3 [2].
CloudFormation: OAC + S3 bucket policy skeleton (adapt fields as needed):
Resources:SiteOAC:Type: AWS::CloudFront::OriginAccessControlProperties:OriginAccessControlConfig:Name: mfe-oacOriginAccessControlOriginType: s3SigningBehavior: alwaysSigningProtocol: sigv4SiteBucketPolicy:Type: AWS::S3::BucketPolicyProperties:Bucket: !Ref SiteBucketPolicyDocument:Version: '2012-10-17'Statement:- Sid: AllowCloudFrontReadEffect: AllowPrincipal:Service: cloudfront.amazonaws.comAction: s3:GetObjectResource: !Sub '${SiteBucket.Arn}/*'Condition:StringEquals:AWS:SourceArn: !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}'
Caching, invalidation, and versioning strategy
Use versioning as the default release mechanism. CloudFront explicitly recommends file versioning when you update files frequently and documents that invalidations wipe all cached variants regardless of headers (important when you vary cache by headers/cookies).
A practical MFE artifact layout:
- Immutable build artifacts:
s3://mfe-bucket/mfe-catalog/1.8.2/assets/app.<hash>.js(cache "long") - One mutable pointer:
s3://mfe-bucket/mfe-catalog/manifest.json(cache "short" or invalidate on release)
CloudFront caching behavior depends on Cache-Control/Expires headers, TTL settings, and versioning practices; AWS documents using Cache-Control headers on S3 objects and combining headers + TTL + invalidations to manage updates.
Security headers: CSP/CORS at CloudFront
CloudFront response headers policies let you add/remove headers on responses CloudFront sends to viewers, and CloudFormation supports configuring a Content-Security-Policy string in a response headers policy.
CloudFormation snippet (CSP via ResponseHeadersPolicy):
Resources:SecurityHeadersPolicy:Type: AWS::CloudFront::ResponseHeadersPolicyProperties:ResponseHeadersPolicyConfig:Name: mfe-security-headersSecurityHeadersConfig:ContentSecurityPolicy:ContentSecurityPolicy: "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"Override: true
CORS can also be managed through response headers policies (or managed policies), which is particularly useful when MFEs are served under one domain and APIs under another.
Cross-MFE state and communication
AWS Prescriptive Guidance recommends event-based cross-interactivity handling for microfrontends that need to react to each other (e.g., global UI behavior) [6]. The safe default is:
- Keep business state inside the MFE boundary.
- Use events for cross-MFE signals (e.g.,
cart.updated,auth.changed). - Prefer BFFs per user experience when APIs would otherwise be overly chatty [7].
Microservice implementation and deployment options
Service templates inside the monorepo
Standardize "service types" so teams don't invent new deployment patterns per service.
Lambda + API Gateway template (serverless)
AWS SAM's AWS::Serverless::Function resource provides shorthand syntax that is transformed into CloudFormation resources during deployment, making it well-suited for service templates in a monorepo.
Minimal SAM template:
AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Resources:OrdersApi:Type: AWS::Serverless::ApiProperties:StageName: prodOrdersFunction:Type: AWS::Serverless::FunctionProperties:Runtime: nodejs20.xHandler: dist/handler.mainCodeUri: .MemorySize: 512Timeout: 10Events:GetOrders:Type: ApiProperties:RestApiId: !Ref OrdersApiPath: /ordersMethod: GET
API Gateway authorization choices you can standardize by service class:
- HTTP APIs: JWT authorizers are first-class for stage/route auth and integrate with OIDC/OAuth2 flows.
- REST APIs: Lambda authorizers support custom auth logic (token or request authorizers).
- Cognito integration: API Gateway can use Cognito user pools as authorizers for REST APIs.
ECS template (containers)
Use ECS with an Application Load Balancer when you need Layer-7 routing and containerized deployments; the ECS docs highlight that ALBs support path-based routing and are commonly used with ECS.
To build images efficiently from a monorepo, use turbo prune --docker to shrink build context, then do a multi-stage Docker build [1].
Docker build flow (conceptual):
# Create pruned build context for the serviceturbo prune services/payments-ecs --docker# Build from pruned outputdocker build -f services/payments-ecs/Dockerfile -t payments:local ./out
Push to ECR uses aws ecr get-login-password | docker login ... and then docker push; AWS documents this exact authentication flow.
EKS template (Kubernetes)
EKS adds a fixed per-cluster control-plane cost, and AWS publishes pricing tiers for standard vs extended Kubernetes version support. Use EKS when multi-service scheduling, Kubernetes-native tooling, and multi-tenant cluster governance are a primary goal—not merely to host a few APIs.
For observability, AWS explicitly documents using AWS Distro for OpenTelemetry (ADOT) to collect metrics/traces for ECS/EKS and send them to X-Ray and other backends.
Table: service runtime trade-offs
| Runtime | Strengths | Costs/risks you must plan for | Best fit |
|---|---|---|---|
| Lambda (+ API Gateway) | Minimal ops; built-in scaling; canary via weighted aliases | Cold start risk; request/compute pricing; packaging size constraints | Spiky APIs, event-driven workloads, "lots of small services" |
| ECS on Fargate (+ ALB) | Container flexibility; ALB routing; blue/green deployments | Always-on baseline cost; capacity tuning; container build/push pipeline | Steady traffic, heavier deps, long-lived connections |
| EKS | Kubernetes ecosystem; standardized platform for many services | Control-plane fee; cluster ops; security hardening and upgrades | Large fleets, K8s-native orgs, shared cluster platforms |
Lambda pricing is request- and duration-based, while Fargate pricing is based on vCPU/memory/ephemeral storage consumption, and EKS adds an explicit per-cluster fee.
CI/CD pipelines, release flows, and environment management
CI strategy: "shared pipeline, scoped execution" as the default
A monorepo does not require "one giant CI job." The scalable pattern is:
- One orchestrating workflow (GitHub Actions or CodePipeline) that:
- Runs
turbo runtasks scoped by--filteror Git ranges - Publishes artifacts only for changed MFEs/services
- Updates the discovery layer (manifest/import map)
- Optionally triggers invalidations for a small set of pointers (manifest/index)
This aligns with Turborepo's own CI guidance: rely on caching + filters rather than complex change detection logic [1].
Table: per-MFE CI vs shared CI
| Model | Pros | Cons | When to choose |
|---|---|---|---|
| Shared CI (one workflow, Turborepo-scoped tasks) | Fast setup; consistent policy; scalable via caching/filters | Requires discipline to avoid coupling in shared steps | Default for most orgs |
| Per-MFE CI (separate workflows/pipelines) | High autonomy; isolated failures | Duplicate config; harder to enforce standards | When teams require independent release cadence and policy |
Remote caching + filter-based execution is what makes the shared-CI model performant [1].
GitHub Actions: concrete pipeline with OIDC to AWS
For secure AWS access from CI, use OIDC (no long-lived AWS keys in secrets). GitHub documents the OIDC-to-AWS model and provides a trust-policy pattern using the sub claim to scope which repo/branch (or environment) may assume a role.
Example workflow (build + deploy changed MFEs; deploy a Lambda service):
name: cion:push:branches: [main]pull_request:permissions:id-token: writecontents: readjobs:build-test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: pnpm/action-setup@v4with:version: 9- name: Installrun: pnpm -w install --frozen-lockfile- name: Turbo build/test (affected)run: |turbo run lint check-types test --cache-dir=.turboturbo run build --filter={./apps/*}[HEAD^1]deploy:if: github.ref == 'refs/heads/main'needs: build-testruns-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: pnpm/action-setup@v4with:version: 9- name: Installrun: pnpm -w install --frozen-lockfile- name: Configure AWS (OIDC)uses: aws-actions/configure-aws-credentials@v4with:role-to-assume: arn:aws:iam::123456789012:role/monorepo-deployeraws-region: us-east-1- name: Build changed MFEsrun: turbo run build --filter={./apps/*}[HEAD^1]- name: Publish MFEs to S3 (example)run: |aws s3 sync apps/mfe-catalog/dist s3://my-mfe-bucket/mfe-catalog/${GITHUB_SHA}/ \--cache-control "public,max-age=31536000,immutable"aws s3 cp infra/manifest/prod.json s3://my-mfe-bucket/manifest.json \--cache-control "public,max-age=60"- name: Deploy Orders Lambda (SAM)run: |cd services/orders-lambdasam buildsam deploy --no-confirm-changeset --stack-name orders-prod
This workflow's authentication model and the need to scope "who can assume the role" are backed by GitHub's OIDC docs and AWS's security guidance on IAM roles for GitHub workflows.
AWS CodeBuild and CodePipeline: concrete examples
CodeBuild buildspec structure
AWS defines buildspec.yml as a YAML collection of commands/settings CodeBuild uses to run builds; it can be stored in-repo and can be overridden per project.
CodeBuild caching CodeBuild supports S3 caching or local caching (including Docker layer cache). S3 caching allows reuse across build hosts and can use dynamic keys (e.g., hash of lockfile).
Example buildspec.yml (monorepo build + ECR push):
version: 0.2phases:install:commands:- corepack enable- pnpm -w install --frozen-lockfilebuild:commands:- turbo run build --filter=services/payments-ecs- turbo prune services/payments-ecs --docker- docker build -t payments:$CODEBUILD_RESOLVED_SOURCE_VERSION ./out- aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY- docker tag payments:$CODEBUILD_RESOLVED_SOURCE_VERSION $ECR_REGISTRY/payments:$CODEBUILD_RESOLVED_SOURCE_VERSION- docker push $ECR_REGISTRY/payments:$CODEBUILD_RESOLVED_SOURCE_VERSIONcache:key: pnpm-$(codebuild-hash-files pnpm-lock.yaml)paths:- 'node_modules/**/*'
The ECR login/push flow is documented by AWS ECR; CodeBuild cache key generation is documented via codebuild-hash-files and cache.key patterns.
CodePipeline
CodePipeline pipelines must have at least two stages with a source stage first; artifacts flow between actions, and CloudFormation provides an AWS::CodePipeline::Pipeline resource for IaC-defined pipelines.
CloudFormation skeleton for a pipeline resource (conceptual):
Resources:Pipeline:Type: AWS::CodePipeline::PipelineProperties:RoleArn: arn:aws:iam::123456789012:role/codepipeline-roleArtifactStore:Type: S3Location: my-pipeline-artifacts-bucketStages:- Name: SourceActions: []- Name: BuildActions: []- Name: DeployActions: []
Environment management: secrets, config, and Turborepo determinism
A production guide should standardize three environment layers:
- Build-time env (affects bundling and test outcomes)
- Deploy-time env (targets AWS accounts/stacks, S3 prefixes, CloudFront IDs)
- Runtime env (service endpoints, secrets, feature flags)
Turborepo supports strict filtering of environment variables; Strict Mode can filter out CI vendor variables unless included through env configuration keys. This is essential for deterministic caching and for preventing "prod build reuses dev cache" [1].
For AWS-side secrets/config:
- Parameter Store
SecureStringuses KMS encryption for sensitive values and is recommended for secret data. - Secrets Manager supports rotation and reduces the need to redeploy clients when credentials rotate.
- CodeBuild and ECS can inject Secrets Manager values as environment variables.
Quality, security, observability, and operational runbooks
Testing strategy across MFEs and services
A practical monorepo guide should mandate four test layers and wire them into Turborepo tasks:
- Unit/component tests per package (fast, cached).
- Contract tests for cross-boundary contracts: event payload schemas, API OpenAPI specs, and MFE exposed module interfaces (for Module Federation).
- Integration tests for real dependencies (service-to-service, MFE-to-BFF).
- E2E tests against a composed staging environment (shell + MFEs + services).
Turborepo task configuration must reflect dependency changes for tasks like check-types, or you risk incorrect green builds when shared package interfaces change [1].
Observability: CDN logs, service traces, and build telemetry
CloudFront logging options include standard access logs and real-time logs attached to cache behaviors; logs include request time, path, response, and processing details useful for debugging MFE asset 404s, cache hit anomalies, and latency regressions.
For service tracing:
- Lambda Active tracing generates trace segments and sends them to X-Ray.
- API Gateway supports X-Ray active tracing for REST APIs (with documented limitations).
- ADOT can collect traces/metrics for ECS/EKS and send them to X-Ray and other backends.
Turborepo also documents an experimental observability mode to export run summaries to OTLP collectors, which you can use to understand CI performance regressions at the task-graph level.
Security runbooks: S3 privacy, CSP/CORS, and auth patterns
S3 privacy: enforce OAC and bucket policies bound to a specific CloudFront distribution ARN to prevent direct S3 access and limit confused-deputy risk [2].
CSP: set CSP using CloudFront response headers policies (or CloudFront Functions/Lambda@Edge response manipulation); CloudFormation supports CSP configuration and override behavior.
CORS: for HTTP APIs, API Gateway supports built-in CORS configuration; for CDN responses, CloudFront response headers policies can standardize CORS headers.
Auth: standardize where auth is enforced:
- At API boundary: API Gateway JWT/Lambda/Cognito authorizers.
- At CDN boundary: CloudFront Functions can validate hashed tokens like JWTs for lightweight authorization decisions; use Lambda@Edge for heavier logic.
Rollout and rollback runbooks: MFEs and services
Microfrontends (static):
- Primary rollback: update manifest/import map pointer to previously known-good versions (no CDN invalidation needed if assets are versioned) [3].
- If you must invalidate: remember invalidation removes all cached variants of the file, regardless of header-based cache variations, so be careful invalidating commonly varied content.
- For CDN config changes: use CloudFront continuous deployment with a staging distribution and weight-based or header-based routing [4].
Lambda services:
- Use versions + aliases; configure weighted routing for canary traffic shifts and fast rollback by moving alias back.
ECS services:
- Use blue/green deployments (ECS + CodeDeploy) to validate new revisions and roll back quickly.
API Gateway:
- Canary releases can be configured per stage (REST APIs), and can be promoted/reset through documented workflows.
Sequential implementation checklist
- Establish repository conventions:
/apps,/services,/packages,/infra; define CODEOWNERS per bounded context; add "do not import MFEs into MFEs" rule. - Add Turborepo with a root
turbo.json; definebuild,test,check-types,lint,dev,deploy; ensure deploy-like tasks arecache: false[1]. - Configure caching correctly: declare
outputsfor build tasks so artifacts restore on cache hits; validate determinism in CI. - Turn on remote caching; configure artifact signing (
remoteCache.signature) and key management (TURBO_REMOTE_CACHE_SIGNATURE_KEY) for integrity. - Configure environment determinism: set
envMode: strict; declareglobalEnv/globalDependencies; document how env changes impact caches. - Implement Boundaries tags/rules: tag MFEs, shared libs, and internal-only packages; block illegal imports.
- Create MFE templates: shell + at least one remote MFE; standardize basePath routing and the mount/export contract.
- Implement discovery: choose manifest (recommended baseline) or import maps; define schema with
name,version,url,fallback[3]. - Choose composition: start with dynamic import/import maps; add Module Federation if you need runtime shared dependency de-duplication.
- Provision S3 buckets for each MFE (or shared bucket with prefixes) and configure CloudFront OAC + bucket policy binding distribution ARN [2].
- Build a CloudFront distribution with path-based behaviors (
/mfe-a/*,/mfe-b/*,/assets/*); attach response headers policy (CSP/CORS). - Add CloudFront Function for SPA routing rewrite to
index.htmlper MFE basePath. - Standardize caching: versioned artifacts for long TTL; short TTL for manifest/import map; avoid frequent invalidations.
- Create service templates: SAM-based Lambda service, ECS container service (with
turbo prune --docker), optional EKS helm-based service. - Implement API auth pattern: JWT authorizers for HTTP APIs where suitable; Lambda/Cognito authorizers for REST APIs; document token/cookie strategy for MFEs.
- Build CI with scoped execution: use
turbo run ... --filter=[git range]; ensure remote cache works in CI [1]. - Implement GitHub Actions OIDC role and least-privilege IAM policies for S3/ECR/CloudFront deploy actions; ban long-lived AWS keys in secrets.
- Implement CodeBuild/CodePipeline alternative: buildspec-driven builds with S3 caching and artifact publishing; pipeline IaC using
AWS::CodePipeline::Pipeline. - Add rollout controls: CloudFront continuous deployment for CDN changes; Lambda weighted aliases; ECS blue/green; API Gateway canary stages [4].
- Add observability: enable CloudFront logs; enable X-Ray for Lambda and API Gateway where supported; deploy ADOT for ECS/EKS telemetry.
- Write operational runbooks: "rollback manifest," "rollback Lambda alias," "rollback ECS via blue/green," "invalidate only pointer files," and incident triage based on CloudFront logs + X-Ray traces.
- Finalize DNS/TLS: request/import ACM cert in
us-east-1for CloudFront and create Route 53 alias record to the distribution.