7.6 KiB
Build-time Environment Variables Configuration Guide
Overview
This guide documents the configuration for build-time environment variables in the Next.js CI/CD pipeline.
Problem Solved: Next.js 16 requires NEXT_PUBLIC_* variables available during npm run build for:
- SEO metadata (
metadataBase) - Sitemap generation
- OpenGraph URLs
- RSS feed URLs
Solution: Create .env file in CI/CD from Gitea secrets, copy to Docker build context, embed variables in JavaScript bundle.
Files Modified
1. .gitea/workflows/main.yml
Changes:
- Added step to create
.envfrom Gitea secrets (after checkout) - Added cleanup step to remove
.envafter Docker push
New Steps:
- name: 📝 Create .env file from Gitea secrets
run: |
echo "Creating .env file for Docker build..."
cat > .env << EOF
# Build-time environment variables
NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
EOF
echo "✅ .env file created successfully"
echo "Preview (secrets masked):"
cat .env | sed 's/=.*/=***MASKED***/g'
- name: 🚀 Push Docker image to registry
run: |
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Clean up sensitive files
rm -f .env
echo "✅ Cleaned up .env file"
2. Dockerfile.nextjs
Changes:
- Added
COPY .env* ./in builder stage (after copying node_modules, before copying source code)
Added Section:
# Copy .env file for build-time variables
# This file is created by CI/CD workflow from Gitea secrets
# NEXT_PUBLIC_* variables are embedded in client-side bundle during build
COPY .env* ./
Position: Between COPY --from=deps /app/node_modules ./node_modules and COPY . .
3. .dockerignore
Changes:
- Modified to allow
.envfile (created by CI/CD) while excluding other.env*files
Updated Section:
# Environment files
.env* # Exclude all .env files
!.env # EXCEPT .env (needed for build from CI/CD)
!.env.example # Keep example
Explanation:
.env*excludes all environment files!.envcreates exception for main.env(from CI/CD).env.local,.env.development,.env.production.localremain excluded
Gitea Repository Configuration
Required Secrets
Navigate to: Repository Settings → Secrets
Add the following secret:
| Secret Name | Value | Type | Description |
|---|---|---|---|
NEXT_PUBLIC_SITE_URL |
https://yourdomain.com |
Secret or Variable | Production site URL |
Notes:
- Can be configured as Secret (masked in logs) or Variable (visible in logs)
- Recommended: Use Variable since it's a public URL
- For sensitive values (API keys), always use Secret
Adding Additional Variables
To add more build-time variables:
-
Add to Gitea Secrets/Variables:
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX NEXT_PUBLIC_API_URL=https://api.example.com -
Update workflow
.envcreation step:cat > .env << EOF NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }} NEXT_PUBLIC_GA_ID=${{ secrets.NEXT_PUBLIC_GA_ID }} NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }} NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 EOF -
No changes needed to Dockerfile or .dockerignore
Testing
Local Testing
-
Create test
.envfile:cat > .env << EOF NEXT_PUBLIC_SITE_URL=http://localhost:3030 NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 EOF -
Build Docker image:
docker build -t mypage:test -f Dockerfile.nextjs . -
Verify variable is embedded (should show "NOT FOUND" - correct behavior):
docker run --rm mypage:test node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL || 'NOT FOUND')"Expected Output:
NOT FOUNDWhy?
NEXT_PUBLIC_*variables are embedded in JavaScript bundle during build, NOT available as runtime environment variables. -
Test application starts:
docker run --rm -p 3030:3030 mypage:testVisit
http://localhost:3030to verify. -
Cleanup:
rm .env docker rmi mypage:test
CI/CD Pipeline Flow
Build Process
- Checkout code (
actions/checkout@v4) - Create
.envfile from Gitea secrets - Build Docker image:
- Stage 1: Install dependencies
- Stage 2: Copy
.env→ Build Next.js (variables embedded in bundle) - Stage 3: Production runtime (no
.envneeded)
- Push image to registry
- Cleanup
.envfile from runner
Deployment Process
- Production server pulls pre-built image
- No
.envfile needed on production server - Variables already embedded in JavaScript bundle
Security Best Practices
✅ Implemented
.envfile created only in CI/CD runner (not committed to git).envcleaned up after Docker push.gitignoreexcludes.envfiles.dockerignoreonly allows.envcreated by CI/CD
⚠️ Important Notes
- DO NOT commit
.envfiles to git repository - DO NOT store secrets in
NEXT_PUBLIC_*variables (they are exposed to client-side) - USE Gitea Secrets for sensitive values (API keys, passwords)
- USE Gitea Variables for non-sensitive config (URLs, feature flags)
🔒 Sensitive Data Guidelines
| Type | Use For | Access |
|---|---|---|
NEXT_PUBLIC_* |
Client-side config (URLs, feature flags) | Public (embedded in JS bundle) |
SECRET_* |
Server-side secrets (API keys, DB passwords) | Private (runtime only) |
Troubleshooting
Issue: Variables not available during build
Symptoms:
- Next.js build errors about missing
NEXT_PUBLIC_SITE_URL - Metadata/sitemap generation fails
Solution:
- Verify
NEXT_PUBLIC_SITE_URLsecret exists in Gitea - Check workflow logs for
.envcreation step - Ensure
.envfile is created BEFORE Docker build
Issue: Variables not working in application
Symptoms:
- URLs show as
undefinedornullin production
Diagnosis:
# Check if variable is in bundle (should work):
curl https://yourdomain.com | grep -o 'NEXT_PUBLIC_SITE_URL'
# Check runtime env (should be empty - correct):
docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"
Solution:
- Verify
.envwas copied during Docker build - Check Dockerfile logs for
COPY .env* ./step - Rebuild with
--no-cacheif needed
Issue: .env file not found during Docker build
Symptoms:
- Docker build warning:
COPY .env* ./- no files matched
Solution:
- Check
.dockerignoreallows.envfile - Verify workflow creates
.envBEFORE Docker build - Check file exists:
ls -la .envin workflow
Verification Checklist
After deploying changes:
- Workflow creates
.envfile (check logs) - Docker build copies
.env(check build logs) - Build succeeds without errors
- Application starts in production
- URLs/metadata display correctly
.envcleaned up after push (security)
Additional Resources
Support
For issues or questions:
- Check workflow logs in Gitea Actions
- Review Docker build logs
- Verify Gitea secrets configuration
- Test locally with sample
.env
Last Updated: 2025-11-24