|
| 1 | +# Issue: ECS Tasks Failing with "next start does not work with output: export" |
| 2 | + |
| 3 | +## Problem Description |
| 4 | + |
| 5 | +After deploying the Next.js application to AWS ECS, the containers were repeatedly starting and then stopping with exit code 1. The deployment workflow was completing successfully, but the ECS service was unable to maintain running tasks. |
| 6 | + |
| 7 | +## Symptoms |
| 8 | + |
| 9 | +- ECS tasks started successfully |
| 10 | +- Container pulled from ECR without issues |
| 11 | +- Application initialized (`✓ Starting...`) |
| 12 | +- Container crashed immediately after startup with exit code 1 |
| 13 | +- ECS service kept trying to start new tasks in a loop |
| 14 | + |
| 15 | +## Error Details |
| 16 | + |
| 17 | +From CloudWatch logs: |
| 18 | + |
| 19 | +``` |
| 20 | +Error: "next start" does not work with "output: export" configuration. |
| 21 | +Use "npx serve@latest out" instead. |
| 22 | + at ignore-listed frames |
| 23 | +``` |
| 24 | + |
| 25 | +## Root Cause |
| 26 | + |
| 27 | +The Next.js configuration had `output: 'export'` set globally, which generates static HTML files. This mode is incompatible with `next start` command used in production deployments. |
| 28 | + |
| 29 | +The issue occurred because: |
| 30 | +1. GitHub Pages deployment requires `output: 'export'` (static site) |
| 31 | +2. AWS ECS deployment requires `output: 'standalone'` (Node.js server) |
| 32 | +3. Both deployments were using the same configuration |
| 33 | + |
| 34 | +## Solution |
| 35 | + |
| 36 | +### 1. Updated `next.config.ts` to conditionally set output mode: |
| 37 | + |
| 38 | +```typescript |
| 39 | +import type { NextConfig } from "next"; |
| 40 | + |
| 41 | +const isGitHubPages = process.env.GITHUB_ACTIONS && process.env.DEPLOY_AWS !== 'true'; |
| 42 | + |
| 43 | +const nextConfig: NextConfig = { |
| 44 | + reactCompiler: true, |
| 45 | + output: isGitHubPages ? 'export' : 'standalone', |
| 46 | + images: { |
| 47 | + unoptimized: true, |
| 48 | + }, |
| 49 | +}; |
| 50 | + |
| 51 | +export default nextConfig; |
| 52 | +``` |
| 53 | + |
| 54 | +### 2. Updated Dockerfile for production-ready standalone mode: |
| 55 | + |
| 56 | +```dockerfile |
| 57 | +FROM node:20-alpine AS base |
| 58 | + |
| 59 | +# Install dependencies |
| 60 | +FROM base AS deps |
| 61 | +RUN apk add --no-cache libc6-compat |
| 62 | +WORKDIR /app |
| 63 | +COPY package.json package-lock.json* ./ |
| 64 | +RUN npm ci |
| 65 | + |
| 66 | +# Build application |
| 67 | +FROM base AS builder |
| 68 | +WORKDIR /app |
| 69 | +COPY --from=deps /app/node_modules ./node_modules |
| 70 | +COPY . . |
| 71 | +ENV NEXT_TELEMETRY_DISABLED=1 |
| 72 | +RUN npm run build |
| 73 | + |
| 74 | +# Production image with standalone output |
| 75 | +FROM base AS runner |
| 76 | +WORKDIR /app |
| 77 | +ENV NODE_ENV=production |
| 78 | +ENV NEXT_TELEMETRY_DISABLED=1 |
| 79 | + |
| 80 | +RUN addgroup --system --gid 1001 nodejs |
| 81 | +RUN adduser --system --uid 1001 nextjs |
| 82 | + |
| 83 | +COPY --from=builder /app/public ./public |
| 84 | +RUN mkdir .next |
| 85 | +RUN chown nextjs:nodejs .next |
| 86 | + |
| 87 | +# Copy standalone output |
| 88 | +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ |
| 89 | +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static |
| 90 | + |
| 91 | +USER nextjs |
| 92 | +EXPOSE 3000 |
| 93 | +ENV PORT=3000 |
| 94 | +ENV HOSTNAME="0.0.0.0" |
| 95 | + |
| 96 | +CMD ["node", "server.js"] |
| 97 | +``` |
| 98 | + |
| 99 | +### 3. Updated GitHub Actions workflow to set environment variable: |
| 100 | + |
| 101 | +```yaml |
| 102 | +- name: Build for GitHub Pages |
| 103 | + if: steps.check-deploy.outputs.deploy_to_aws == 'false' |
| 104 | + working-directory: ./aws-deploy-guide |
| 105 | + run: npm run build |
| 106 | + env: |
| 107 | + NEXT_PUBLIC_BASE_PATH: '' |
| 108 | + DEPLOY_AWS: 'false' |
| 109 | +``` |
| 110 | +
|
| 111 | +## Verification |
| 112 | +
|
| 113 | +After implementing the fix: |
| 114 | +
|
| 115 | +1. **AWS ECS Deployment**: Container starts successfully with `standalone` mode |
| 116 | + ``` |
| 117 | + ▲ Next.js 16.0.5 |
| 118 | + - Local: http://ip-172-31-12-97.us-west-2.compute.internal:3000 |
| 119 | + - Network: http://ip-172-31-12-97.us-west-2.compute.internal:3000 |
| 120 | + ✓ Starting... |
| 121 | + ✓ Ready in 293ms |
| 122 | + ``` |
| 123 | +
|
| 124 | +2. **GitHub Pages Deployment**: Static files generated correctly with `export` mode |
| 125 | +
|
| 126 | +## Key Takeaways |
| 127 | +
|
| 128 | +- Next.js `output: 'export'` is for static sites only (no server required) |
| 129 | +- Next.js `output: 'standalone'` is for production Node.js servers |
| 130 | +- Use environment variables to conditionally configure build modes |
| 131 | +- Always check CloudWatch logs for ECS container failures |
| 132 | +- Use multi-stage Docker builds for optimized production images |
| 133 | +
|
| 134 | +## Commands Used for Debugging |
| 135 | +
|
| 136 | +```powershell |
| 137 | +# Check ECS task status |
| 138 | +aws ecs describe-tasks --cluster CLUSTER_NAME --tasks TASK_ARN --region REGION |
| 139 | +
|
| 140 | +# View CloudWatch logs |
| 141 | +aws logs tail /ecs/TASK_DEFINITION_NAME --since 1h --region REGION |
| 142 | +
|
| 143 | +# Test container locally |
| 144 | +docker build -t aws-deploy-guide . |
| 145 | +docker run -p 3000:3000 aws-deploy-guide |
| 146 | +``` |
| 147 | + |
| 148 | +## Related Documentation |
| 149 | + |
| 150 | +- [Next.js Static Exports](https://nextjs.org/docs/app/building-your-application/deploying/static-exports) |
| 151 | +- [Next.js Standalone Output](https://nextjs.org/docs/app/api-reference/next-config-js/output) |
| 152 | +- [AWS ECS Task Definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html) |
0 commit comments