Skip to content

Multi-Environment Configuration Strategy

Status: Implemented Current State: The application uses standard Vite Environment Variables (VITE_*) to configure AWS Amplify.


1. Environment Variable Strategy

We follow the 12-Factor App methodology, storing configuration in the environment. This decouples the build artifact from the configuration, allowing the same codebase to be deployed to Development, Staging, or Production simply by changing the environment variables.

Variables

Variable Description
VITE_APPSYNC_ENDPOINT The AppSync GraphQL Endpoint URL. (Renamed to avoid Amplify conflicts)
VITE_USER_POOL_ID The Cognito User Pool ID.
VITE_USER_POOL_CLIENT_ID The Cognito User Pool App Client ID.
VITE_COGNITO_DOMAIN The Cognito OAuth Domain (without https://).
VITE_REDIRECT_URL The Base URL for redirects (e.g., http://localhost:5173 or https://chatkcal.app).

Configuration Files

.env (Local Development Defaults) Contains the safe, public configuration for the Test/Dev Stack. This is committed to git so that bun run dev works immediately for any developer.

VITE_APPSYNC_ENDPOINT=https://77tzkmeswfcf3mxham6cx3pvk4.appsync-api.ap-southeast-2.amazonaws.com/graphql
VITE_USER_POOL_ID=ap-southeast-2_JzQaTK8eY
# ...

.env.dev (Dev Deployment) Configuration for the deployed dev environment (e.g. Amplify Console "dev" branch).

VITE_APPSYNC_ENDPOINT=https://77tzkmeswfcf3mxham6cx3pvk4.appsync-api.ap-southeast-2.amazonaws.com/graphql
VITE_REDIRECT_URL=https://dev.d3ftkdqo7pe962.amplifyapp.com

.env.production (Prod Deployment) Configuration for the production environment.

VITE_APPSYNC_ENDPOINT=https://q7xlrivnljedhpfu6ctnlknpeq.appsync-api.ap-southeast-2.amazonaws.com/graphql
VITE_REDIRECT_URL=https://chatkcal.app

CI/CD (Amplify Console) For deployed environments, ensure these variables are set in the AWS Amplify Console > Environment Variables settings.


2. Implementation in amplify.config.js

Refactored amplify.config.js loads these values directly using import.meta.env.

Amplify.configure({
    Auth: {
        Cognito: {
            userPoolId: import.meta.env.VITE_USER_POOL_ID,
            // ...
        }
    },
    API: {
        GraphQL: {
            endpoint: import.meta.env.VITE_APPSYNC_ENDPOINT,
            // ...
        }
    }
});

3. Rationale & Use Cases

Why Environment Variables?

Previously, we used a hardcoded switch in amplify.config.js. Moving to .env variables provides:

  1. Flexibility: We can point the frontend to any backend stack (e.g., a Feature Branch stack) without changing code.
  2. Parity: It aligns with standard frontend practices (Vite, Next.js, Create React App).
  3. Security: It encourages the separation of config from code.

The "Hybrid" Environment Scenario

A common requirement in our workflow is to run a Dev Backend (to test API changes) while using the Prod User Pool (to log in with real accounts and data).

  • Scenario: Developer wants to test a new GraphQL resolver but needs their actual user ID.

  • Setup: Create a local .env.local file that overrides specific variables:

    # .env.local
    VITE_USER_POOL_ID=<PROD_USER_POOL_ID>
    VITE_APPSYNC_ENDPOINT=<DEV_GRAPHQL_ENDPOINT>
    

4. Security Note: Committing .env Files

Question: Should these files be committed to Git?

Answer:

  • YES: For files containing public configuration (.env, .env.production, .env.dev).
    • Variables like VITE_USER_POOL_ID and VITE_APPSYNC_ENDPOINT are not secrets. They are exposed to the client browser in the JavaScript bundle anyway. Committing them ensures consistent builds across teams and CI/CD and easier onboarding.
  • NO: For files containing secrets or local overrides (e.g., .env.local, .env.secret).
    • If you ever need to store an API Key or Secret Key locally, use .env.secret or .env.local and ensure it is listed in .gitignore.

5. Build Configuration (amplify.yml)

To ensure the correct .env file is loaded during the build process on AWS Amplify, we use an amplify.yml specification in the project root. Since our application code lives in the frontend/ subdirectory, we use the Monorepo structure with the applications key.

Logic:

  • Pre-Build: Installs dependencies using bun.
  • Build: Checks the AWS_BRANCH environment variable (provided automatically by Amplify).
    • If AWS_BRANCH is dev: Runs bun run build --mode dev. This tells Vite to load .env + .env.dev.
    • Otherwise (e.g. main): Runs bun run build. This defaults to production mode and loads .env + .env.production.
version: 1
applications:
  - appRoot: frontend
    frontend:
      phases:
        preBuild:
          commands:
            - bun install
        build:
          commands:
            - if [ "${AWS_BRANCH}" = "dev" ]; then bun run build --mode dev; 
              else bun run build; fi
      artifacts:
        baseDirectory: dist
        files:
          - '**/*'
      cache:
        paths:
          - node_modules/**/*